home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / grafik / bildanzeiger / seepix / source.lha / FS.c < prev    next >
C/C++ Source or Header  |  1992-11-27  |  79KB  |  3,448 lines

  1. /**FS.c******************************************************************
  2.  *                                    *
  3.  *   SeePix -- by Hank Schafer                        *
  4.  *                                    *
  5.  *   SeePix is an IFF Picture Viewer.  It works with Lo-Res,        *
  6.  *   Med-Res, Hi-Res, HAM, and EHB formats.  I'm working on support     *
  7.  *   for X-Specs, and Anim5 formats.                    *
  8.  *                                    *
  9.  *   SeePix is based on a program by Olaf Barthel, called        *
  10.  *   'LoadImage'.  As released, LoadImage had a couple of bugs.     *
  11.  *   The Amiga-Key alternatives to menu use didn't all work.  That's    *
  12.  *   been fixed.  There were two separate print functions in LoadImage    *
  13.  *   which behaved exactly the same.  The redundancy was eliminated.    *
  14.  *   LoadImage used the Topaz ROMFONT, and made no allowances for a    *
  15.  *   different system default font (under 2.04).  I added a built-in    *
  16.  *   font.  I've reworked the code considerably from the original       *
  17.  *   release, to allow for optimizations based on time and space.    *
  18.  *                                    *
  19.  *   SeePix features a palette tool which allows "tweaking" of colors    *
  20.  *   prior to printing, allowing you to modify the color printout to    *
  21.  *   more closely resemble the original graphics (Blue is Blue, not    *
  22.  *   Purple).  SeePix can be Iconified.  SeePix features an ARP     *
  23.  *   interface.  SeePix now uses the PathMaster File Selector.        *
  24.  *                                    *
  25.  ************************************************************************
  26.  *                                                                      *
  27.  *   SeePix Copyright © 1992 by Hank Schafer; all rights reserved.      *
  28.  *                                                                      *
  29.  *   This program is free software; you can redistribute it and/or      *
  30.  *   modify it under the terms of the GNU General Public License as     *
  31.  *   published by the Free Software Foundation, either version 1, or    *
  32.  *   (at your option) any later version.                                *
  33.  *                                                                      *
  34.  *   This program is distributed in the hope that it will be useful,    *
  35.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of     *
  36.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  *
  37.  *   General Public License for more details.                           *
  38.  *                                                                      *
  39.  *   You should have received a copy of the GNU General Public License  *
  40.  *   along with this program; if not, write to:                         *
  41.  *                 Free Software Foundation, Inc.                       *
  42.  *                 675 Massachusetts Ave.                               *
  43.  *                 Cambridge  MA  02139, USA                            *
  44.  *                                                                      *
  45.  **************** Special Function Copyright Notices ********************
  46.  *                                    *
  47.  ****LoadImage Copyright Notice:                    *
  48.  *                                    *
  49.  *   LoadImage is © Copyright 1988, 1989, 1990 by MXM, all rights    *
  50.  *   reserved, written by Olaf Barthel.  No guarantees of any kind are    *
  51.  *   made that this program is 100% reliable.  Use this program on    *
  52.  *   your own risk!                            *
  53.  *                                    *
  54.  ****Iconify Copyright Notice:                        *
  55.  *                                    *
  56.  *   Copyright 1987 by Leo L. Schwab.                    *
  57.  *   Permission is hereby granted for use in any and all programs,    *
  58.  *   both Public Domain and commercial in nature, provided this     *
  59.  *   Copyright notice is left intact.                    *
  60.  *                                    *
  61.  ****ColorWindow (Palette) Copyright Notice:                *
  62.  *                                    *
  63.  * ColorWindow Routine    --  Color Window Routines            *
  64.  *     from Book 1 of the Amiga Programmers' Suite by RJ Mical          *
  65.  *                                    *
  66.  * Copyright (C) 1986, 1987, Robert J. Mical                *
  67.  * All Rights Reserved.                         *
  68.  *                                    *
  69.  ****PathMaster Copyright Notice:                    *
  70.  *                                    *
  71.  * -------------------------------------------------------------------- *
  72.  *   Copyright © 1989 Justin V. McCormick.  All Rights Reserved.    *
  73.  * -------------------------------------------------------------------- *
  74.  *                                    *
  75.  *    The PathMaster name is a trademark of Justin V. McCormick.    *
  76.  *                                    *
  77.  *   PathMaster File Selector source and documentation written by:    *
  78.  *                                    *
  79.  *             Justin V. McCormick.                *
  80.  *           Copyright © 1989 by Justin V. McCormick.         *
  81.  *             All Rights Reserved.                *
  82.  *                                    *
  83.  * -------------------------------------------------------------------- *
  84.  ************************************************************************
  85.  *                                    *
  86.  *   Hope this is something you can use and enjoy.            *
  87.  *                                    *
  88.  ************************************************************************/
  89.  
  90. #include "Config.h"
  91.  
  92. #ifdef    PATHMASTER
  93.  
  94. #asm
  95.  
  96.     INCLUDE    "Exec/Types.i"
  97.     INCLUDE "Exec/Nodes.i"
  98.     INCLUDE "Exec/Lists.i"
  99.  
  100. SYS    MACRO    *
  101.     IFGT    NARG-2
  102.     FAIL    !!!
  103.     ENDC
  104.     IFEQ    NARG-2
  105.     MOVE.L    \2,a6
  106.     ENDC
  107.     JSR    _LVO\1(a6)
  108.     ENDM
  109.  
  110. XLVO    MACRO    *
  111.     XREF    _LVO\1
  112.     ENDM
  113.  
  114. ; These three equate control the size of the path, file, and
  115. ; pattern string limits
  116.  
  117. PATHSTRSIZE    EQU    300
  118. FILESTRSIZE    EQU    32
  119. MATCHSTRSIZE    EQU    32
  120.  
  121. AUTOKNOB    EQU    $1
  122. FREEVERT    EQU    $4
  123. PROPBORDERLESS    EQU    $8
  124. MEMF_CLEAR     EQU    $10000
  125. WINDOWSIZING    EQU    $1
  126. WINDOWDRAG    EQU    $2
  127. WINDOWDEPTH    EQU    $4
  128. WINDOWCLOSE    EQU    $8
  129. WINDOWTGADS    EQU    WINDOWDRAG!WINDOWDEPTH!WINDOWCLOSE
  130. FPEN        EQU    1
  131. DPEN        EQU    3
  132.  
  133. fib_DirEntryType EQU    $4
  134. fib_FileName    EQU    $8
  135. fib_Size    EQU    $7C
  136. fib_DateStamp    EQU    $84
  137. fib_SIZEOF    EQU    $104
  138.  
  139. gg_Flags    EQU    $C
  140. id_SIZEOF    EQU    $24
  141. it_FrontPen    EQU    $0
  142. it_IText    EQU    $C
  143. rp_AreaPtrn    EQU    $8
  144. rp_AreaPtSz    EQU    $1D
  145. wd_Flags    EQU    $18
  146. wd_RPort    EQU    $32
  147.  
  148.     STRUCTURE FSRequest,0
  149.     STRUCT    fs_dirname,PATHSTRSIZE
  150.     STRUCT    fs_filename,FILESTRSIZE
  151.     STRUCT    fs_matchpattern,MATCHSTRSIZE
  152.     WORD    fs_leftedge
  153.     WORD    fs_topedge
  154.     WORD    fs_sorttype
  155.     UWORD    fs_flags
  156.     ULONG    fs_windowflags
  157.     CPTR    fs_fullname
  158.     CPTR    fs_ignorepattern
  159.     CPTR    fs_pathgadstr
  160.     CPTR    fs_filegadstr
  161.     CPTR    fs_titlestr
  162.     CPTR    fs_readingstr
  163.     CPTR    fs_sortingstr
  164.     CPTR    fs_emptydirstr
  165.     CPTR    fs_nomatchstr
  166.     CPTR    fs_selectfilestr
  167.     CPTR    fs_selectstr
  168.     CPTR    fs_cancelstr
  169.     CPTR    fs_specgadstr
  170.     CPTR    fs_userscreen
  171.     CPTR    fs_userport
  172.     CPTR    fs_specgadfunc
  173.     CPTR    fs_dirfunc
  174.     CPTR    fs_filefunc
  175.     CPTR    fs_userfunc
  176.     CPTR    fs_initfunc
  177.     CPTR    fs_matchfunc
  178.     LABEL    fs_SIZEOF
  179.  
  180.     STRUCTURE node_data,0
  181.     STRUCT    nd_alphadata,58
  182.     WORD    nd_filetype
  183.     WORD    nd_showit
  184.     WORD    nd_textcolor
  185.     WORD    nd_namelength
  186.     ULONG    nd_filesize
  187.     ULONG    nd_days
  188.     ULONG    nd_minutes
  189.     ULONG    nd_ticks
  190.     LABEL    nd_SIZEOF
  191.  
  192.     STRUCTURE file_node,0
  193.     STRUCT    fn_Node,MLN_SIZE
  194.     CPTR    fn_info
  195.     WORD    fn_idnum
  196.     LABEL    fn_SIZEOF
  197.  
  198.     STRUCTURE dev_node,0
  199.     STRUCT    dn_Node,MLN_SIZE
  200.     STRUCT    dn_name,32
  201.     LABEL    dn_SIZEOF
  202.  
  203.     XREF    _AlphaGad
  204.     XREF    _ColonStr
  205.     XREF    _CurDevNames
  206.     XREF    _DevGads
  207.     XREF    _devList
  208.     XREF    _DevTxts
  209.     XREF    _DOSBase
  210.     XREF    _EmptyPattern
  211.     XREF    _FileUndoBuffer
  212.     XREF    _FileUndoName
  213.     XREF    _fnList
  214.     XREF    _fsbaddatestr
  215.     XREF    _FSCountDown
  216.     XREF    _fscurmicros
  217.     XREF    _fscursecs
  218.     XREF    _fsdatefmtstr
  219.     XREF    _fsdayspermonth
  220.     XREF    _FSDirFmtStr
  221.     XREF    _fsdirlocked
  222.     XREF    _FSDone
  223.     XREF    _FSDownGad
  224.     XREF    _fserrmsgs
  225.     XREF    _FSFib
  226.     XREF    _FSFileGad
  227.     XREF    _FSFileInfo
  228.     XREF    _FSFileNodes
  229.     XREF    _fsflags
  230.     XREF    _FSIgnorePat
  231.     XREF    _FSInfo
  232.     XREF    _FSLock
  233.     XREF    _fsneedshow
  234.     XREF    _FSNextDevs
  235.     XREF    _fsnumentries
  236.     XREF    _fsoldmicros
  237.     XREF    _fsoldsecs
  238.     XREF    _FSPathBuf
  239.     XREF    _FSPathGad
  240.     XREF    _FSPathInfo
  241.     XREF    _FSPatternGad
  242.     XREF    _FSPatternInfo
  243.     XREF    _FSPatternUndoBuffer
  244.     XREF    _FSPrevDevs
  245.     XREF    _fsprevgadid
  246.     XREF    _FSReq
  247.     XREF    _FSRPort
  248.     XREF    _FSSizeFmtStr
  249.     XREF    _FSSlideGad
  250.     XREF    _FSSlideProp
  251.     XREF    _fsstartedstr
  252.     XREF    _fstempdate
  253.     XREF    _fstitlelength
  254.     XREF    _fstitstatus
  255.     XREF    _FSUndoGad
  256.     XREF    _FSUpGad
  257.     XREF    _FSUserGad
  258.     XREF    _fsvheight
  259.     XREF    _fsvirgindir
  260.     XREF    _fsvposition
  261.     XREF    _FSWin
  262.     XREF    _FSWinTitleStr
  263.     XREF    _FSwstr
  264.     XREF    _GfxBase
  265.     XREF    _IntuitionBase
  266.     XREF    _lastdev
  267.     XREF    _NIL2Gad
  268.     XREF    _OldFSPathBuf
  269.     XREF    _RamDirNameStr
  270.     XREF    _SizeGad
  271.     XREF    _SlashStr
  272.     XREF    _TimeGad
  273.     XREF    _topfin
  274.  
  275.     XREF    _sprintf
  276.     XREF    _FSVBDelay
  277.  
  278.     IFD    BENCHMARK
  279.     XREF    _StartTime
  280.     XREF    _StopTime
  281.     XREF    _timermsg1
  282.     ENDC
  283.  
  284.     XLVO    ActivateGadget
  285.     XLVO    AddHead
  286.     XLVO    AddTail
  287.     XLVO    AllocMem
  288.     XLVO    ClipBlit
  289.     XLVO    DisplayBeep
  290.     XLVO    DoubleClick
  291.     XLVO    Examine
  292.     XLVO    ExNext
  293.     XLVO    FreeMem
  294.     XLVO    GetMsg
  295.     XLVO    Insert
  296.     XLVO    IoErr
  297.     XLVO    Move
  298.     XLVO    NewModifyProp
  299.     XLVO    ParentDir
  300.     XLVO    RectFill
  301.     XLVO    RefreshGList
  302.     XLVO    RemHead
  303.     XLVO    ReplyMsg
  304.     XLVO    SetAPen
  305.     XLVO    SetDrMd
  306.     XLVO    SetWindowTitles
  307.     XLVO    Text
  308.     XLVO    UnLock
  309.  
  310.     SECTION    CODE
  311.  
  312. ; LONG MyActivateGad(gadget, window)
  313. ;   struct Gadget *gadget;
  314. ;   struct Window *window;
  315. ;
  316. ; Activate a gadget, wait till it is ready.  Try up to 3 times.  Returns
  317. ; TRUE (1) if it succeeded, FALSE (0) if it failed to activate.
  318.  
  319.     XDEF    _MyActivateGad
  320. _MyActivateGad:
  321.     movem.l    d2/a2/a6,-(sp)
  322.     moveq    #2,d2            ;Try 3 times to activate gadget
  323.  
  324. 1$    movem.l    16(sp),a0/a1        ;Grab gadget pointer, window pointer
  325.     suba.l    a2,a2            ;No requester pointer
  326.     movea.l    _IntuitionBase,a6
  327.     jsr    _LVOActivateGadget(a6)    ;Activate!
  328.     tst.l    d0            ;Did it catch?
  329.      bne.s    2$            ;Yep, move on
  330.  
  331.     pea    5
  332.     jsr    _FSVBDelay
  333.     addq.w    #4,sp
  334.     dbf    d2,1$
  335. 2$
  336.     movem.l    (sp)+,d2/a2/a6
  337.     rts
  338.  
  339.  
  340. ; LONG FSCheckFlagChange(VOID);
  341.  
  342.     XDEF    _FSCheckFlagChange
  343. _FSCheckFlagChange:
  344.  
  345.     movea.l    _FSReq,a0
  346.     move.w    fs_flags(a0),d0
  347.     move.w    _fsflags,d1
  348.     andi.w    #%00011000,d0
  349.     andi.w    #%00011000,d1
  350.     cmp.w    d0,d1            ;FS_SHOW_FILES_FIRST or FS_SHOW_DIRS_FIRST changed?
  351.      beq.s    1$            ;Nope
  352.     move.w    #1,_fsvirgindir    ;Else we need to re-read the directory
  353. 1$
  354.     move.w    fs_flags(a0),d0
  355.     move.w    _fsflags,d1
  356.     andi.w    #%01100000,d0
  357.     andi.w    #%01100000,d1
  358.     cmp.w    d0,d1            ;FS_SHOW_FILES_ONLY or FS_SHOW_DIRS_ONLY changed?
  359.      beq.s    2$            ;Nope
  360.     moveq    #1,d0            ;Else flag that we need to FSMatchPattern()
  361.     bra.s    3$
  362. 2$
  363.     moveq    #0,d0
  364. 3$
  365.     move.w    fs_flags(a0),_fsflags ;Reset flags to match FSReq now
  366.     rts
  367.  
  368.  
  369. ; Assign device name texts to intuitexts in the 4 Device Gadgets
  370.  
  371.     XDEF    _SetDevGads
  372. _SetDevGads:
  373.     movem.l    d3-d4/a2-a3/a5,-(sp)
  374.  
  375. ;for (i = 0, tnode = lastdev; i < 4;)
  376.     moveq    #0,d4            ;d4 = i = 0
  377.     movea.l    _lastdev,a2        ;a2 = tnode = lastdev
  378.     move.l    a2,d3            ;Copy for comparison
  379.     lea    _CurDevNames,a3    ;a3 = &CurDevNames[0]
  380.     lea    _DevTxts,a5        ;a5 = &DevTxts[0]
  381.  
  382. 1$
  383.     lea    dn_name(a2),a1
  384.     move.l    a1,0(a3,d4.w)        ;CurDevNames[i] = tnode->name
  385.  
  386.     moveq    #4,d0
  387.     move.l    0(a5,d4.w),a0
  388.     movea.l    it_IText(a0),a0
  389.     jsr    astrncpy        ;astrncpy (DevTxts[i]->IText, tnode->name, 4)
  390.  
  391.     addq.w    #4,d4            ;i++
  392.  
  393.     movea.l    dn_Node+MLN_SUCC(a2),a2    ;tnode = tnode->dn_Node.mln_Succ
  394.     tst.l    dn_Node+MLN_SUCC(a2)    ;if (tnode->dn_Node.mln_Succ == 0)
  395.      bne.s    2$            ;Nope
  396.     movea.l    _devList,a2
  397.     movea.l    MLH_HEAD(a2),a2        ;Else start the listing over at the start
  398. 2$
  399.     cmpa.l    d3,a2            ;Have we already shown this node?
  400.      beq.s    3$            ;Yep, disable the rest
  401.  
  402.     cmpi.w    #16,d4            ;Set all 4 Device gadgets yet?
  403.      bcs    1$            ;Nope, do next
  404.  
  405. 3$
  406.  
  407. ; Disable any leftover gadgets
  408. ;for (; i < 4; i++)
  409.  
  410.     lea    _DevGads,a0
  411.     bra.s    5$
  412.  
  413. 4$    movea.l    0(a0,d4.w),a1
  414.     bset.b    #0,gg_Flags(a1)        ;DevGads[i]->Flags |= GADGDISABLED
  415.     addq.w    #4,d4
  416.  
  417. 5$    cmpi.w    #16,d4
  418.      bcs    4$
  419.  
  420.     movem.l    (sp)+,d3-d4/a2-a3/a5
  421.     rts
  422.  
  423.  
  424. ; FSScrollDevGads(direction)
  425. ;   WORD direction;
  426.  
  427.     XDEF    _FSScrollDevGads
  428. _FSScrollDevGads:
  429.     movem.l    a2/a6,-(sp)
  430.  
  431.     movea.l    _lastdev,a0
  432.     tst.w    12+2(sp)        ;Grab scroll direction
  433.      beq.s    1$            ;If zero, scroll to next
  434.  
  435. ; Bump list pointer one direction or the other
  436.     move.l    dn_Node+MLN_SUCC(a0),a0    ;Get successor
  437.     tst.l    dn_Node+MLN_SUCC(a0)    ;EndoList?
  438.      bne.s    2$            ;Nope
  439.     movea.l _devList,a0
  440.     movea.l    MLH_HEAD(a0),a0        ;Else lastdev = devList->lh_Head
  441.     bra.s    2$
  442. 1$
  443.     movea.l    dn_Node+MLN_PRED(a0),a0 ;Else, lastdev = lastdev->next
  444.     tst.l    dn_Node+MLN_PRED(a0)    ;Endolist?
  445.      bne.s    2$
  446.     movea.l _devList,a0
  447.     movea.l    MLH_TAILPRED(a0),a0    ;Else lastdev = devList->lh_TailPred
  448. 2$
  449.     move.l    a0,_lastdev
  450.     jsr    _SetDevGads        ;Set the gadget text fields
  451.  
  452. ; Refresh gadget texts
  453. ; RefreshGList(&NIL2Gad, FSWin, 0L, 4L);
  454.     moveq    #4,d0
  455.     suba.l    a2,a2
  456.     movea.l    _FSWin,a1
  457.     lea    _NIL2Gad,a0
  458.     SYS    RefreshGList,_IntuitionBase
  459.  
  460.     movem.l    (sp)+,a2/a6
  461.     rts
  462.  
  463.  
  464. ; CheckFSArrows()
  465. ; See if the Up or Down arrow gadgets are currently activated, scroll
  466. ; the file display area or device gadget list if so.
  467.  
  468.     XDEF    _CheckFSArrows
  469. _CheckFSArrows:
  470.     subq.w    #1,_FSCountDown
  471.      bge.s    12$
  472.  
  473.     btst.b    #7,_FSUpGad+gg_Flags+1    ;FSUpGad.Flags & SELECTED?
  474.      beq.s    2$            ;Nope, maybe FSDownGad
  475.     pea    1            ;Otherwise scroll filegadgets up
  476.     bra.s    3$
  477.  
  478. 2$    btst.b    #7,_FSDownGad+gg_Flags+1     ;FSDownGad.Flags & SELECTED?
  479.      beq.s    4$            ;Nope, maybe slide gadget is selected
  480.     pea    0            ;Otherwise scroll filegadgets down
  481.  
  482. 3$    jsr    _FSScrollFileGads
  483.     addq.w    #4,sp
  484.     move.w    #0,_FSCountDown    ;Set timer to wake up in .02 secs.
  485.     bra.s    12$
  486.  
  487. 4$    btst.b    #7,_FSSlideGad+gg_Flags+1    ;FSSlideGad.Flags & SELECTED?
  488.      beq.s    5$            ;Nope, maybe UpDev
  489.     jsr    _FSDoSlideGadget    ;Process slide gadget motion
  490.     move.w    #0,_FSCountDown    ;Set timer to wake up in .02 secs.
  491.     bra.s    12$
  492.  
  493. 5$    btst.b    #7,_FSPrevDevs+gg_Flags+1    ;FSPrevDevs.Flags & SELECTED?
  494.      beq.s    7$            ;Nope, maybe DownDev
  495.     pea    1            ;Otherwise FSScrollDevGads(1);
  496. 6$    jsr    _FSScrollDevGads
  497.     addq.w    #4,sp
  498.     move.w    #1,_FSCountDown    ;Set timer to wake up in .16 secs.
  499.     bra.s    12$
  500.  
  501. 7$    btst.b    #7,_FSNextDevs+gg_Flags+1    ;FSNextDevs.Flags & SELECTED?
  502.      beq.s    10$            ;Nope, nothing of interest, slow down
  503.     pea    0            ;Else FSScrollDevGads(0);
  504.     bra    6$
  505.  
  506. 10$
  507.     move.w    #4,_FSCountDown
  508. 12$
  509.     rts
  510.  
  511.  
  512. ; BYTE *FibFileDate(fib_date)
  513. ; struct DateStamp *fib_date;
  514. ;
  515. ; Calculate date based on DateStamp structure and return a pointer
  516. ; to the formatted date text.
  517.  
  518.     XDEF    _FibFileDate
  519. _FibFileDate:
  520.     link    a5,#0
  521.     movem.l    d3-d7,-(sp)
  522.  
  523.     movea.l    8(a5),a1        ;Grab datestamp pointer
  524.     moveq    #78,d7            ;Initial year = 1978
  525.  
  526.     move.l    (a1),d5            ;days = fib_date->ds_Days
  527.      blt    ffdbaddate        ;Hey! you can't be negative! Invalid date...
  528.  
  529. ; Determine what year it is
  530.     divu    #1461,d5
  531.     move.l    d5,d0            ;Stash it
  532.     ext.l    d5
  533.     lsl.l    #2,d5
  534.     add.l    d5,d7            ;year += (days / 1461) * 4
  535.  
  536. ; Count how many months into that year
  537. ffdgetmo:
  538.     swap    d0
  539.     moveq    #0,d5
  540.     move.w    d0,d5            ;days %= 1461
  541.  
  542. 1$    tst.w    d5            ;Out of days yet?
  543.      beq.s    3$            ;Yep, done here
  544.  
  545.     move.w    #365,d6            ;Else month_days = 365
  546.     move.w    d7,d0            ;Grab year
  547.     andi.w    #3,d0            ;if (year & 3) == 0 Leap year?
  548.      bne.s    2$            ;Nope
  549.     addq.w    #1,d6            ;Otherwise bump month_days
  550.  
  551. 2$    cmp.w    d6,d5            ;is day < month_days?
  552.      bcs.s    3$            ;yep, done here
  553.     sub.w    d6,d5            ;otherwise day -= month_days
  554.  
  555.     addq.l    #1,d7            ; year++
  556.     bra    1$
  557. 3$
  558.  
  559. ; Count how many days into that month of that year
  560. ffdgetday:
  561. ; for (i = 0, day++; i < 12; i++)
  562.     moveq    #0,d4            ;current month = 0
  563.     moveq    #0,d6            ;Zap hinybs
  564.     addq.w    #1,d5
  565.     lea    _fsdayspermonth,a0
  566.  
  567. 1$    move.b    0(a0,d4.w),d6        ;month_days = _fsdayspermonth[i]
  568.  
  569.     cmpi.w    #1,d4            ;if (i == 1 && (year & 3) == 0)
  570.      bne.s    2$
  571.     move.w    d7,d0
  572.     andi.w    #3,d0
  573.      bne.s    2$
  574.     addq.w    #1,d6            ;month_days++
  575.  
  576. 2$    cmp.w    d6,d5            ;if (day <= month_days)
  577.      ble.s    4$            ;Break out, found the right month
  578.  
  579.     sub.w    d6,d5            ;Else, day -= month_days
  580.  
  581.     addq.w    #1,d4            ;i++
  582. 3$    cmpi.w    #12,d4            ;Done all months yet?
  583.      bcs    1$            ;Nope
  584.  
  585. 4$
  586. ffdprint:
  587. 1$    cmpi.l    #99,d7            ;while (year >= 100)
  588.      ble.s    2$
  589.     subi.l    #100,d7            ;year -= 100
  590.     bra    1$
  591. 2$
  592. ;sprintf(_fstempdate, "%02ld-%02ld-%02ld %02ld:%02ld:%02ld", year, i + 1, day, hour, min, sec)
  593.     move.l    8(a1),d0        ;sec = fib_date->ds_Tick / 50;
  594.     divu.w    #50,d0
  595.     ext.l    d0
  596.     move.l    d0,-(sp)        ;Push secs
  597.  
  598.     moveq    #0,d0            ;Zap reg
  599.     move.w    6(a1),d0        ;min = fib_date->ds_Minute
  600.     move.w    d0,d1            ;Clone it
  601.     divu    #60,d0
  602.     move.w    d0,d3            ;hour = min / 60
  603.     ext.l    d3
  604.     mulu    #60,d0
  605.     sub.w    d0,d1            ;min -= hour * 60
  606.     ext.l    d1
  607.     move.l    d1,-(sp)        ;Push mins
  608.  
  609.     move.l    d3,-(sp)        ;Push hours
  610.     move.l    d5,-(sp)        ;Push day of month
  611.     addq.w    #1,d4            ;Push month (offset by 1!)
  612.     move.l    d4,-(sp)
  613.     move.l    d7,-(sp)        ;Push year
  614.     pea    _fsdatefmtstr    ;Push the format pattern
  615.     pea    _fstempdate        ;Push destination buffer
  616.     jsr    _sprintf
  617.     lea    32(sp),sp
  618.     lea    _fstempdate,a0
  619.     move.l    a0,d0            ;return((BYTE *)&_fstempdate[0])
  620.  
  621. ffddone:
  622.     movem.l    (sp)+,d3-d7
  623.     unlk    a5
  624.     rts
  625.  
  626. ffdbaddate:
  627.     lea    _fsbaddatestr,a0
  628.     move.l    a0,d0            ;return (" <Invalid Date> ")
  629.     bra    ffddone
  630.  
  631.  
  632.     XDEF    _FSSetKnobHeight
  633. _FSSetKnobHeight:
  634. ; vheight = (ULONG)( 655350L / (long)fsnumentries );
  635.     move.w    _fsnumentries,d1
  636.     cmpi.w    #10,d1
  637.      bhi.s    1$
  638.     move.w    #$ffff,_fsvheight
  639.     rts
  640. 1$
  641.     move.l    #655350,d0
  642.     divu    d1,d0
  643.     move.w    d0,_fsvheight
  644. 3$
  645.     rts
  646.  
  647.  
  648.     XDEF    _FSSetKnobPos
  649. _FSSetKnobPos:
  650.     movea.l    _topfin,a0
  651.     moveq    #0,d0
  652.     move.w    fn_idnum(a0),d0
  653.     swap    d0
  654.     move.w    _fsnumentries,d1
  655.     subi.w    #10,d1
  656.      bhi.s    1$
  657.     moveq    #0,d0
  658.     bra.s    2$
  659. 1$
  660.     divu    d1,d0
  661.      bvc.s    2$
  662.     move.w    #$ffff,d0
  663. 2$
  664.     move.w    d0,_fsvposition
  665.     rts
  666.  
  667.  
  668.     XDEF    _FSResetKnob
  669. _FSResetKnob:
  670.     jsr    _FSSetKnobHeight
  671.     jsr    _FSSetKnob
  672.     rts
  673.  
  674.  
  675. ; FSSetKnob()
  676. ;  Call ModifyProp() to actually update slide image in window.
  677.  
  678.     XDEF    _FSSetKnob
  679. _FSSetKnob:
  680.     movem.l    d2-d5/a2/a6,-(sp)
  681.  
  682. ; NewModifyProp(&FSSlideGad, FSWin, 0L, AUTOKNOB|FREEVERT|PROPB, 0L, vposition, 0xffffL, vheight, 1L)
  683.     lea    _FSSlideGad,a0
  684.     movea.l    _FSWin,a1
  685.     suba.l    a2,a2
  686.     moveq    #AUTOKNOB!FREEVERT!PROPBORDERLESS,d0
  687.     moveq    #0,d1
  688.     moveq    #0,d2
  689.     move.w    _fsvposition,d2
  690.     move.l    #$ffff,d3
  691.     moveq    #0,d4
  692.     move.w    _fsvheight,d4
  693.     moveq    #1,d5
  694.     SYS    NewModifyProp,_IntuitionBase
  695.  
  696.     movem.l    (sp)+,d2-d5/a2/a6
  697.     rts
  698.  
  699.  
  700. ; FSEnableFGad(gadg_num)
  701. ;  LONG gadg_num;
  702. ;
  703. ; Given a file gadget number, refresh the text for that entry.
  704.  
  705.     XDEF    _FSEnableFGad
  706. _FSEnableFGad:
  707.     movem.l    a2-a3/a6,-(sp)
  708.  
  709.     movea.l    _FSRPort,a2
  710.  
  711.     move.w  4+4*3+2(sp),d0        ;Grab gadget number
  712.     move.w    d0,d1            ;Copy
  713.     lsl.w    #2,d0            ;Conver to long offset
  714.     lea    _FSFileNodes,a0
  715.     movea.l    0(a0,d0.w),a0        ;tnode = FSFileNodes[gadg_num]
  716.     movea.l    fn_info(a0),a3        ;a3 = tnode->info
  717.  
  718. ; Move to the right slot text position
  719.     mulu    #11,d1
  720.     addi.w    #19,d1
  721.     moveq    #9,d0
  722.     movea.l    a2,a1
  723.     SYS    Move,_GfxBase    ;Move(FSRPort, 9, gadnum*11+19)
  724.  
  725. ; Set the pen color according to the node
  726.     move.w    nd_textcolor(a3),d0
  727.     movea.l    a2,a1
  728.     SYS    SetAPen            ;SetAPen(FSRPort, tinfo->textcolor)
  729.  
  730. ; Blast out the text
  731.     moveq    #56,d0
  732.     lea    nd_alphadata(a3),a0
  733.     movea.l    a2,a1
  734.     SYS    Text            ;Text(FSRPort, tinfo->alphadata, 56)
  735.  
  736.     movem.l    (sp)+,a2-a3/a6
  737.     rts
  738.  
  739.  
  740. ; FSDisableFGad(gadg_num)
  741. ;  LONG gadg_num;
  742. ;
  743. ; Given a file gadget number, fill that slot with the EmptyPattern
  744. ; and clear the FileNode[] slot for that gadget.
  745.  
  746.     XDEF    _FSDisableFGad
  747. _FSDisableFGad:
  748.     movem.l    d2-d4/a2/a6,-(sp)
  749.  
  750.     move.w    4*5+4+2(sp),d4        ;Grab gadget number
  751.  
  752.     movea.l    _FSRPort,a2
  753.  
  754.     lea    _EmptyPattern,a0
  755.     move.l    a0,rp_AreaPtrn(a2)    ;rp->AreaPtrn = EmptyPattern
  756.     move.b    #1,rp_AreaPtSz(a2)    ;rp->AreaPtSz = (BYTE)1
  757.  
  758.     movea.l    a2,a1
  759.     moveq    #2,d0
  760.     SYS    SetAPen,_GfxBase     ;SetAPen(rp, 2)
  761.  
  762.     move.w    d4,d1
  763.     mulu    #11,d1
  764.     addi.w    #13,d1            ;miny = 13L + (gadg_num * 11)
  765.  
  766.     move.l    d1,d3
  767.     addq.w    #7,d3            ;maxy = miny + 7L
  768.  
  769.     movea.l    a2,a1            ;FSWin->RPort
  770.     moveq    #9,d0            ;minx
  771.     move.l    #456,d2            ;maxx
  772.     SYS    RectFill        ;RectFill(rp, minx, miny, maxx, maxy)
  773.  
  774.     clr.l    rp_AreaPtrn(a2)        ;rp->AreaPtrn = 0L
  775.     clr.b    rp_AreaPtSz(a2)        ;rp->AreaPtSz = (BYTE)0
  776.  
  777.     move.w    d4,d0
  778.     lsl.w    #2,d0
  779.     lea    _FSFileNodes,a0
  780.     clr.l    0(a0,d0.w)        ;FSFileNodes[gadg_num] = 0L
  781.  
  782.     movem.l    (sp)+,d2-d4/a2/a6
  783.     rts
  784.  
  785.  
  786.     XDEF    _FSDisableAllFGads
  787. _FSDisableAllFGads:
  788.     move.l    d2,-(sp)
  789.  
  790.     moveq    #0,d2
  791.     move.w    _fsnumentries,d2
  792.     bra.s    2$
  793. 1$    move.l    d2,-(sp)
  794.     jsr    _FSDisableFGad        ;FSDisableFGad(i)
  795.     addq.w    #4,sp
  796.     addq.w    #1,d2            ;i++
  797. 2$    cmpi.w    #10,d2            ;Hit 10 entries?
  798.      bcs    1$            ;Nope, disable one
  799.     move.l    (sp)+,d2
  800.     rts
  801.  
  802.  
  803. ;struct file_node *AllocFileNode()
  804. ;
  805. ;  Allocate a file_node structure and it's info block, return pointer
  806. ; to the file_node or NULL if allocation failed.
  807.  
  808.     XDEF    _AllocFileNode
  809. _AllocFileNode:
  810.     move.l    a6,-(sp)
  811.  
  812.     moveq    #fn_SIZEOF+nd_SIZEOF,d0    ;sizeof(struct file_node)+sizeof(struct node_data)
  813.     move.l    #MEMF_CLEAR,d1        ;MEMF_CLEAR
  814.     SYS    AllocMem,4        ;Allocate file node structure
  815.     move.l    d0,d1
  816.      beq.s    1$
  817.     movea.l    d0,a0
  818.     addi.l    #fn_SIZEOF,d1
  819.     move.l    d1,fn_info(a0)        ;Set pointer to tnode->info area
  820. 1$
  821.     movea.l    (sp)+,a6
  822.     rts
  823.  
  824.  
  825. ; FreeFileNode(tnode)
  826. ;  struct file_node *tnode;
  827. ;
  828. ;  Given a pointer to a file_node, Free the memory allocated for that node.
  829.  
  830.     XDEF    _FreeFileNode
  831. _FreeFileNode:
  832.     move.l    a6,-(sp)
  833.  
  834.     move.l    4+4(sp),d0        ;Grab tnode
  835.      beq.s    2$            ;Nope, get outta here
  836.     movea.l    d0,a1
  837.     moveq    #fn_SIZEOF+nd_SIZEOF,d0
  838.     SYS    FreeMem,4        ;FreeMem(tnode, sizeof(struct file_node)+sizeof(struct node_data))
  839.  
  840. 2$    movea.l    (sp)+,a6
  841.     rts
  842.  
  843.  
  844.  
  845. ; FreeAllFNodes()
  846. ;
  847. ;  Call FreeFileNode for each node in the linked list of file_nodes,
  848. ;then deallocate the head of the list (fnList)
  849.  
  850.     XDEF    _FreeAllFNodes
  851. _FreeAllFNodes:
  852.     movem.l    a2/a6,-(sp)
  853.  
  854.     move.l    _fnList,d0        ;Is there a list?
  855.      beq.s    2$            ;Nope, get outta here
  856.  
  857.     movea.l    d0,a2            ;Grab head
  858.     movea.l    4,a6            ;Set for ExecBase
  859. 1$
  860.     movea.l    a2,a0
  861.     SYS    RemHead            ;d0 = RemHead(fnList)
  862.     tst.l    d0            ;Hit end?
  863.      beq.s    2$            ;yep
  864.  
  865.     move.l    d0,-(sp)
  866.     jsr    _FreeFileNode        ;Free the node
  867.     addq.w    #4,sp
  868.     bra    1$            ;Remove next node
  869.  
  870. 2$
  871. ; Reset other globals
  872.     clr.w    _fsvposition    ;Set slider position to top of area
  873.     move.w    #$ffff,_fsvheight    ;Max height
  874.     clr.w    _fsnumentries    ;Zero entries
  875.  
  876.     movem.l    (sp)+,a2/a6
  877.     rts
  878.  
  879.  
  880. ;struct dev_node *AllocDevNode()
  881. ;
  882. ;  Allocate a dev_node, return pointer to same
  883.  
  884.     XDEF    _AllocDevNode
  885. _AllocDevNode:
  886.     move.l    a6,-(sp)
  887.  
  888.     moveq    #dn_SIZEOF,d0
  889.     move.l    #MEMF_CLEAR,d1
  890.     SYS    AllocMem,4        ;AllocMem(sizeof(struct dev_node), MEMF_CLEAR)
  891.  
  892.     movea.l    (sp)+,a6
  893.     rts
  894.  
  895.  
  896. ;FreeDevNode(tnode)
  897. ;  struct dev_node *tnode;
  898. ;
  899. ;  Given a pointer to a dev_node, free memory allocated for that node.
  900.  
  901.     XDEF    _FreeDevNode
  902. _FreeDevNode:
  903.     move.l    a6,-(sp)
  904.  
  905.     move.l    4+4(sp),d0        ;Grab dev_node to free
  906.      beq.s    1$            ;Oops, nothing here
  907.  
  908.     movea.l    d0,a1
  909.     moveq    #dn_SIZEOF,d0
  910.     SYS    FreeMem,4        ;FreeMem(tnode, (long)sizeof(struct dev_node))
  911.  
  912. 1$
  913.     movea.l    (sp)+,a6
  914.     rts
  915.  
  916.  
  917.  
  918. ;FreeAllDNodes()
  919. ;
  920. ;  Call FreeDevNode() for each dev_node in the linked list, then free the
  921. ; head of the list, devList.
  922.  
  923.     XDEF    _FreeAllDNodes
  924. _FreeAllDNodes:
  925.     movem.l    a2/a6,-(sp)
  926.  
  927.     move.l    _devList,d0        ;Is there a head node?
  928.      beq.s    3$            ;Nope, don't deallocate
  929.  
  930.     movea.l    d0,a2            ;Grab head of device list
  931.     movea.l    4,a6            ;Set for execbase
  932.  
  933. 1$    movea.l    a2,a0
  934.     SYS    RemHead            ;d0 = RemHead(devList)
  935.     tst.l    d0            ;Got one?
  936.      beq.s    2$            ;Nope, list is empty
  937.  
  938.     move.l    d0,-(sp)
  939.     jsr    _FreeDevNode        ;Free this device node
  940.     addq.w    #4,sp
  941.     bra    1$
  942.  
  943. 2$    movea.l    a2,a1
  944.     moveq    #MLH_SIZE,d0
  945.     SYS    FreeMem            ;FreeMem(devList, sizeof(MinList))
  946.     clr.l    _devList
  947.  
  948. 3$    movem.l    (sp)+,a2/a6
  949.     rts
  950.  
  951.  
  952. ; FreeFileSelect()
  953. ;   Deallocate filenames and fileinfoblocks, unlock any locks
  954.  
  955.     XDEF    _FreeFileSelect
  956. _FreeFileSelect:
  957.     move.l    a6,-(sp)
  958.     move.w    #1,_fsvirgindir    ;virgindir = 1
  959.     jsr    _FreeAllFNodes        ;Free all allocated filenames
  960.     jsr    _FSClearLock        ;Unlock any locks
  961.  
  962. ; Free the head node itself
  963.     move.l    _fnList,d0
  964.      beq.s    1$
  965.     movea.l    d0,a1
  966.     moveq    #MLH_SIZE,d0
  967.     SYS    FreeMem,4        ;FreeMem(fnList, sizeof(MinList))
  968.     clr.l    _fnList        ;And clear the pointer
  969. 1$
  970. ; Free the global FileInfoBlock and InfoData struct
  971.     move.l    _FSFib,d0        ;Do we have a FileInfoBlock allocated?
  972.      beq.s    2$            ;Nope
  973.     movea.l    d0,a1
  974.     move.l    #fib_SIZEOF+id_SIZEOF,d0
  975.     SYS    FreeMem,4        ;FreeMem(FSFib, 300L)
  976.     clr.l    _FSFib        ;Set to NULL so we don't re-free it
  977.     clr.l    _FSInfo
  978. 2$
  979.     movea.l    (sp)+,a6
  980.     rts
  981.  
  982.  
  983. ; Cleanup function for fileselect
  984.  
  985.     XDEF    _ReleaseFileSelect
  986. _ReleaseFileSelect:
  987.     jsr    _FreeFileSelect
  988.     jsr    _FreeAllDNodes
  989.     rts
  990.  
  991.  
  992. ; LONG FSGetNextFib(VOID)
  993. ;
  994. ; Call ExNext() to fill in next FileInfoBlock, set titlebar to reflect
  995. ; status of the request.
  996.  
  997.     XDEF    _FSGetNextFib
  998. _FSGetNextFib:
  999.     movem.l    d2/a6,-(sp)
  1000.  
  1001. * Try to get next fileinfoblock from dos
  1002.     move.l    _FSLock,d1
  1003.     move.l    _FSFib,d2
  1004.     SYS    ExNext,_DOSBase
  1005.     tst.l    d0            ;Did we get an entry?
  1006.      bne.s    gnfgot1            ;Yep, got it
  1007.  
  1008. ; Didn't get one, find out why
  1009. ; if ( (error = IoErr()) != ERROR_NO_MORE_ENTRIES)
  1010.     SYS    IoErr            ;Get error number
  1011.     cmpi.l    #232,d0            ;No more entries?
  1012.      beq.s    gnfnme            ;Yep
  1013.  
  1014.     move.l    d0,-(sp)
  1015.     jsr    _ioerrnum        ;Otherwise set window title to error number
  1016.     addq.w    #4,sp
  1017.     move.w    d0,_fstitstatus
  1018.     moveq    #-1,d2            ;Return bad get status
  1019.     bra.s    gnfsetwintit
  1020.  
  1021. gnfnme:
  1022.     moveq    #0,d2            ;Return DONE!
  1023.     tst.w    _fsnumentries    ;Got any valid pattern matches?
  1024.      bne.s    gnfselect        ;Yep, select a file time
  1025.  
  1026.     movea.l    _fnList,a6
  1027.     movea.l    MLH_HEAD(a6),a6
  1028.     tst.l    fn_Node+MLN_SUCC(a6)     ;Do we have any files?
  1029.      beq.s    gnfnoentry        ;Nope, no entries
  1030.  
  1031.     move.w    #24,_fstitstatus    ;Otherwise no match
  1032.     bra.s    gnfsetwintit
  1033.  
  1034. gnfnoentry:
  1035.     move.w    #22,_fstitstatus    ;No Entries...
  1036.     bra.s    gnfsetwintit
  1037.  
  1038. gnfselect:
  1039.     move.w    #29,_fstitstatus    ;Select a file...
  1040.  
  1041. gnfsetwintit:
  1042.     bra.s    gnfdone
  1043.  
  1044. gnfgot1:
  1045.     moveq    #1,d2
  1046.  
  1047. gnfdone:
  1048.     move.l    d2,d0
  1049.     movem.l    (sp)+,d2/a6
  1050.     rts
  1051.  
  1052.  
  1053. ;AllocFSFib()
  1054. ;Allocate a fileinfoblock, return status
  1055.  
  1056.     XDEF    _AllocFSFib
  1057. _AllocFSFib:
  1058.     move.l    a6,-(sp)
  1059.     tst.l    _FSFib        ;Do we already have a fib?
  1060.      bne.s    1$            ;Yep, get out of here
  1061.  
  1062. ;FSFib = AllocMem(sizeof(*FSFib) + sizeof(*FSInfo), MEMF_CLEAR);
  1063.     move.l    #fib_SIZEOF+id_SIZEOF,d0
  1064.     move.l    #MEMF_CLEAR,d1
  1065.     SYS    AllocMem,4
  1066.     move.l    d0,_FSFib
  1067.      beq.s    2$            ;Oops, allocation failed, return 0
  1068.  
  1069.     addi.l    #fib_SIZEOF,d0
  1070.     move.l    d0,_FSInfo        ;Set pointer to InfoData struct too
  1071.  
  1072. 1$    moveq    #1,d0            ;Return good status
  1073.  
  1074. 2$    movea.l    (sp)+,a6
  1075.     rts
  1076.  
  1077.  
  1078. ;LONG ioerrnum(num)
  1079. ;  LONG num;
  1080. ;
  1081. ; Given an IoErr number, convert to error text table offset, return
  1082. ; converted index number.
  1083.  
  1084.     XDEF    _ioerrnum
  1085. _ioerrnum:
  1086.     move.l    4(sp),d0
  1087.  
  1088.     cmpi.w    #202,d0            ;if (num < 202L || num > 231L)
  1089.      bcs.s    ioetl
  1090.     cmpi.w    #231,d0
  1091.      bls.s    ioe3l
  1092. ioetl:
  1093.     moveq    #27,d0            ;return(27)
  1094.     rts
  1095. ioe3l:
  1096.     cmpi.w    #209,d0            ;if (num < 209L)
  1097.      bcc.s    ioe4l
  1098.     subi.w    #202,d0            ;num -= 202L
  1099.     rts
  1100. ioe4l:
  1101.     subi.w    #205,d0            ;else num -= 205L
  1102.     rts
  1103.  
  1104.  
  1105. ; BYTE *ioerrmsg(num)
  1106. ;  long num;
  1107. ;
  1108. ;  Given a IoErr number, return pointer to error message text that
  1109. ; describes that error.
  1110.  
  1111.     XDEF    _ioerrmsg
  1112. _ioerrmsg:
  1113.     move.l    4(sp),-(sp)        ;Push error number
  1114.     jsr    _ioerrnum
  1115.     addq.w    #4,sp
  1116.     lsl.w    #2,d0            ;Convert return to text table offset
  1117.     lea    _fserrmsgs,a0
  1118.     move.l    0(a0,d0.w),d0        ;Return pointer to fserrmsgs[num]
  1119.     rts
  1120.  
  1121.  
  1122. ; VOID FSPutPath(VOID)
  1123. ;  Refresh the FSPathGadget imagery.
  1124.  
  1125.     XDEF    _FSPutPath
  1126. _FSPutPath:
  1127.     movem.l    a2/a6,-(sp)
  1128.  
  1129. ;RefreshGList(&FSPathGad, FSWin, 0L, 1L);
  1130.     lea    _FSPathGad,a0
  1131.     movea.l    _FSWin,a1
  1132.     suba.l    a2,a2
  1133.     moveq    #1,d0
  1134.     SYS    RefreshGList,_IntuitionBase
  1135.  
  1136.     movem.l    (sp)+,a2/a6
  1137.     rts
  1138.  
  1139.  
  1140. ; VOID FSClearLock(VOID)
  1141. ;
  1142. ;  If we have a Lock on the current directory, unlock it.
  1143.  
  1144.     XDEF    _FSClearLock
  1145. _FSClearLock:
  1146.     move.l    a6,-(sp)
  1147.     tst.w    _fsdirlocked    ;Is it locked?
  1148.      beq.s    2$            ;Nope, don't dare unlock
  1149.  
  1150.     move.l    _FSLock,d1
  1151.      beq.s    1$
  1152.     SYS    UnLock,_DOSBase    ;UnLock(FSLock)
  1153.     clr.l    _FSLock        ;FSLock = 0L;
  1154. 1$    clr.w    _fsdirlocked    ;dirlocked = 0
  1155.  
  1156. 2$    movea.l    (sp)+,a6
  1157.     rts
  1158.  
  1159.  
  1160. ; FSWinTitle()
  1161. ;   Refresh current window title using contents of windowtitle[].
  1162.  
  1163.     XDEF    _FSWinTitle
  1164. _FSWinTitle:
  1165.     movem.l    a2/a6,-(sp)
  1166.  
  1167.     move.w    _fstitlelength,d0
  1168.     lea    _FSWinTitleStr,a0
  1169.     clr.b    0(a0,d0.w)        ;windowtitle[fstitlelength] = '\x0'
  1170.  
  1171.     move.w    _fstitstatus,d1
  1172.     lsl.w    #2,d1
  1173.     lea    _fserrmsgs,a1
  1174.     movea.l    0(a1,d1.w),a1
  1175.     adda.w    d0,a0
  1176.     jsr    astrcpy            ;astrcpy(&windowtitle[fstitlelength], fserrmsgs[fstitstatus])
  1177.  
  1178.     movea.l    _FSWin,a1
  1179.     move.l    wd_Flags(a1),d0        ;d0 = FSWin->Flags
  1180.     andi.l    #WINDOWTGADS,d0     ;Do we have titlebar gadgets?
  1181.      bne.s    3$            ;Yep, refresh is automatic
  1182.  
  1183.     lea    _FSWinTitleStr+79,a1
  1184.     clr.b    (a1)            ;FSWinTitleStr[79] = 0
  1185.     move.b    #' ',d0            ;for (;ptr != &FSWinTitle[79];ptr++)
  1186. 2$    cmpa.l    a0,a1
  1187.      beq.s    4$
  1188.     move.b    d0,(a0)+        ;*ptr = ' '
  1189.     bra    2$
  1190. 3$
  1191.     move.b    #' ',(a0)+        ;Concat a space and a null onto the end
  1192.     clr.b    (a0)
  1193. 4$
  1194. ;SetWindowTitles(FSWin, windowtitle, -1L)
  1195.     movea.l    _FSWin,a0
  1196.     lea    _FSWinTitleStr,a1
  1197.     movea.l    #-1,a2
  1198.     SYS    SetWindowTitles,_IntuitionBase
  1199.  
  1200.     movem.l    (sp)+,a2/a6
  1201.     rts
  1202.  
  1203.  
  1204. ; VOID FSEndString(VOID)
  1205. ;
  1206. ; If user started a string gadget entry then clicked in another gadget,
  1207. ;ignore any changes to the string and restore the previous string.
  1208.  
  1209.     XDEF    _FSEndString
  1210. _FSEndString:
  1211.     movem.l    a2/a6,-(sp)
  1212.  
  1213.     move.w    _fsstartedstr,d0    ;Grab starttext flag
  1214.     cmpi.w    #1,d0            ;Did user start at file entry?
  1215.      bne.s    fstnotfile        ;Nope
  1216.  
  1217.     movea.l    _FSFileInfo,a0    ;Grab filename buffer
  1218.     lea    _FileUndoName,a1
  1219.     lea    _FSFileGad,a2    ;Grab filetext gadget
  1220.     bra.s    fstrefresh        ;Refresh it
  1221.  
  1222. fstnotfile:
  1223.     cmpi.w    #2,d0            ;Did user start a path entry?
  1224.      bne.s    fstnotpath        ;Nope, maybe pattern
  1225.  
  1226.     movea.l    _FSPathInfo,a0    ;Grab pathtext buffer
  1227.     lea    _FileUndoBuffer,a1
  1228.     lea    _FSPathGad,a2    ;Pointer to path gadget
  1229.     bra.s    fstrefresh        ;Refresh text
  1230.  
  1231. fstnotpath:
  1232.     cmpi.w    #3,d0            ;Started a pattern entry?
  1233.      bne.s    fstdone            ;Nope, don't have to do anything
  1234.  
  1235.     movea.l    _FSPatternInfo,a0    ;Else grab the pattern buffer
  1236.     lea    _FSPatternUndoBuffer,a1
  1237.     lea    _FSPatternGad,a2    ;Pointer to pattern gadget
  1238.  
  1239. fstrefresh:
  1240.     jsr    astrcpy            ;astrcpy(tstr, FSwstr)
  1241.  
  1242.     movea.l    a2,a0
  1243.     movea.l    _FSWin,a1
  1244.     suba.l    a2,a2
  1245.     moveq    #1,d0
  1246.     SYS    RefreshGList,_IntuitionBase ;RefreshGList(tgad, FSWin, 0L, 1L)
  1247.  
  1248.     clr.w    _fsstartedstr    ;fsstartedstr = 0
  1249.  
  1250. fstdone:
  1251.     movem.l    (sp)+,a2/a6
  1252.     rts
  1253.  
  1254.  
  1255.  
  1256. ; FSDoGadget(gadgid)
  1257. ;  ULONG gadgid;
  1258. ;
  1259. ; Given a gadget id number, perform action associated with that gadget.
  1260.  
  1261.     XDEF    _FSDoGadget
  1262. _FSDoGadget:
  1263.     movem.l    d4/a2,-(sp)
  1264.  
  1265.     move.w    14(sp),d4        ;Grab gadget id number
  1266.      bne.s    dgnotusergad        ;Not zero, not Undo gadget
  1267.  
  1268. ; FSUserGad
  1269.     jsr    _ConcatPathString     ;Concat final output text, return
  1270.     clr.w    _FSDone
  1271.  
  1272.     movea.l    _FSReq,a1
  1273.     movea.l    fs_specgadfunc(a1),a0
  1274.     pea    _FSUserGad
  1275.     move.l    _FSWin,-(sp)
  1276.     move.l    a1,-(sp)
  1277.     jsr    (a0)
  1278.     lea    12(sp),sp
  1279.     tst.l    d0
  1280.      bne    dgnewdir
  1281.     bra    dogaddone
  1282.  
  1283. dgnotusergad:
  1284. ; FSSelectGad
  1285.     cmpi.w    #1,d4            ;Is the the FSSelect gadget?
  1286.      bne.s    dgnotselect        ;Nope
  1287.     jsr    _ConcatPathString     ;Concat final output text, return
  1288.     bra    dogaddone
  1289.  
  1290. dgnotselect:
  1291. ; FSCancelGad
  1292.     cmpi.w    #2,d4            ;Is it the FSCancel Gadget?
  1293.      bne.s    dgnotcancel        ;Nope
  1294.     move.w    #1,_FSDone        ;Global signal that we're done
  1295.     movea.l    _FSReq,a0        ;a0 = fsreq
  1296.     movea.l    fs_fullname(a0),a0    ;a0 = fsreq->fullname
  1297.     clr.b    (a0)            ;Return filename == ""
  1298.     bra    dogaddone
  1299.  
  1300. dgnotcancel:
  1301. ; UndoGad
  1302.     cmpi.w    #3,d4            ;Undo?
  1303.      bne.s    dgnotundo
  1304.     movea.l    _FSPathInfo,a0    ;Copy OldFSPathBuf to FSPathInfo.Buffer
  1305.     movea.l    _OldFSPathBuf,a1
  1306.     jsr    astrcpy            ;astrcpy(FSPathInfo.Buffer, OldFSPathBuf)
  1307.     bra    dgnewdir        ;Process new directory
  1308.  
  1309. dgnotundo:
  1310. ; Dev1Gad
  1311.     cmpi.w    #20,d4            ;Is it the first Device Gadget?
  1312.      bne.s    dgnotram        ;Nope
  1313.     movea.l    _CurDevNames+12,a1    ;Push the name text
  1314. dgdevs:
  1315.     movea.l    _FSPathInfo,a0    ;Destination text
  1316.     jsr    astrcpy            ;Copy new path
  1317.     bra    dgnewdir        ;Now set new directory
  1318.  
  1319. dgnotram:
  1320.     cmpi.w    #21,d4            ;Is it the second Device Gadget?
  1321.      bne.s    dgnotdf0        ;Nope
  1322.     movea.l    _CurDevNames+8,a1    ;Push the name text
  1323.     bra    dgdevs            ;Change path
  1324.  
  1325. dgnotdf0:
  1326.     cmpi.w    #22,d4            ;Is it the third Device Gadget?
  1327.      bne.s    dgnotnil1        ;Nope
  1328.     movea.l    _CurDevNames+4,a1    ;Push the name text
  1329.     bra    dgdevs            ;Set the path
  1330.  
  1331. dgnotnil1:
  1332.     cmpi.w    #23,d4            ;Is it the fourth Device Gadget?
  1333.      bne.s    dgnotnil2        ;Nope
  1334.     movea.l    _CurDevNames,a1    ;Push the name text
  1335.     bra    dgdevs            ;And set the new path
  1336.  
  1337. dgnotnil2:
  1338. ; RootGad
  1339.     cmpi.w    #24,d4            ;Is it the ROOT gadget?
  1340.      bne.s    dgnotroot        ;Nope
  1341.     jsr    _SetRootDir        ;Set root directory!
  1342.     bra    dogaddone        ;Done
  1343.  
  1344. dgnotroot:
  1345. ; ParentGad
  1346.     cmpi.w    #25,d4            ;Is it the Parent gadget?
  1347.      bne.s    dgnotpar        ;Nope
  1348.     jsr    _SetParentDir        ;Change to parent directory
  1349.     bra    dogaddone        ;Done!
  1350.  
  1351. dgnotpar:
  1352. ; FSPatternGad
  1353.     cmpi.w    #30,d4            ;Maybe its the pattern text gadget?
  1354.      bne.s    dgnotpattern
  1355.     jsr    _FSMatchPattern        ;Otherwise attempt to match new pattern
  1356.     bra    dogaddone        ;We're done!
  1357.  
  1358. dgnotpattern:
  1359. ; FSFileGad
  1360.     cmpi.w    #31,d4            ;Is it the file text gadget?
  1361.      bne.s    dgnotfileg        ;Nope
  1362.     jsr    _FSFileFunc
  1363.     jsr    _ConcatPathString    ;Form final path text
  1364.     btst.b    #1,_fsflags+1    ;FS_NO_STRING_EXIT?
  1365.      beq    dogaddone
  1366.     clr.w    _FSDone
  1367.     bra    dogaddone
  1368. 1$
  1369.     movea.l    _FSFileInfo,a0
  1370.     tst.b    (a0)            ;Really a filename here?
  1371.      bne.s    2$            ;yep
  1372.     btst.b    #2,_fsflags+1    ;FS_NO_STRING_OKAY?
  1373.      beq.s  2$            ;Nope
  1374.      bra    dogaddone        ;let user exit with no filename
  1375. 2$
  1376.     clr.w    _FSDone        ;Else we ain't done yet!
  1377.     bra    dogaddone
  1378.  
  1379. dgnotfileg:
  1380. ; FSPathGad
  1381.     cmpi.w    #32,d4            ;Is it the path text gadget?
  1382.      bne.s    dgnotpath        ;Nope
  1383.     movea.l    _FSPathInfo,a2    ;Grab pointer to path text
  1384.     movea.l    a2,a0
  1385.     jsr    astrlen            ;Determine length
  1386.     subq.w    #1,d0            ;Move back to last BYTE
  1387.      blt.s    dgnotdamnsla        ;Oops, null text!
  1388.  
  1389.     cmpi.b    #'/',0(a2,d0.w)        ;Is the last char a slash?
  1390.      bne.s    dgnotdamnsla        ;Nope, don't have to tromp it
  1391.  
  1392. 1$    cmpi.b    #'/',0(a2,d0.w)        ;Check for a trailing slash
  1393.      bne.s    2$            ;Didn't find another
  1394.     clr.b    0(a2,d0.w)        ;Clobber this slash
  1395.     subq.w    #1,d0            ;Dec character pointer
  1396.      bne.s    1$            ;till we run out of slashes or chars
  1397.  
  1398. 2$    jsr    _FSPutPath        ;Refresh path text
  1399. dgnotdamnsla:
  1400.     jsr    _FSDirFunc        ;Do fsreq->dirfunc, if there is one
  1401.     tst.w    d0            ;Ignore new dir?
  1402.      beq.s    1$            ;Nope
  1403.     jsr    _SetParentDir        ;Else chop off the new path
  1404.     jsr    _FSPutPath        ;Update string gad
  1405.     clr.w    _fsvirgindir    ;Virgin again
  1406.     bra.s    dogaddone        ;All done
  1407. 1$
  1408.     move.l    _FSWin,-(sp)
  1409.     pea    _FSFileGad
  1410.     jsr    _MyActivateGad        ;Activate file text gadget
  1411.     addq.w    #8,sp
  1412.     bra.s    dgnewdir        ;Set new path, read new dir
  1413.  
  1414. dgnotpath:
  1415. ; Slide Gadget
  1416.     cmpi.w    #33,d4            ;Is it the SlideGadget?
  1417.      bne.s    dgnotslide        ;nope
  1418.     jsr    _FSDoSlideGadget    ;Else it's been released, update position
  1419.     bra.s    dgresetarrows        ;Done here, reset timer
  1420.  
  1421. dgnotslide:
  1422. ; Arrow gadgets
  1423.     cmpi.w    #40,d4            ;Is it one of the four arrows gadgets?
  1424.      blt.s    dogaddone
  1425.     cmpi.w    #43,d4
  1426.      bgt.s    dogaddone
  1427. dgresetarrows:
  1428.     clr.w    _FSCountDown    ;Kill any timer requests in progress
  1429.     bra.s    dogaddone
  1430.  
  1431. dgnewdir:
  1432.     move.w    #1,_fsvirgindir    ;Set flag to read new directory!
  1433.  
  1434. dogaddone:
  1435.     movem.l    (sp)+,d4/a2
  1436.     rts
  1437.  
  1438.  
  1439. ; VOID FillFileNode(tnode)
  1440. ;   struct file_node *tnode;
  1441.  
  1442. ffnnode    EQU    4+4*4
  1443.  
  1444.     XDEF    _FillFileNode
  1445. _FillFileNode:
  1446.     movem.l    d2/a2-a3/a6,-(sp)
  1447.  
  1448.     movea.l    ffnnode(sp),a0        ;a0 = tnode passed
  1449.     movea.l    fn_info(a0),a2        ;a2 = tinfo = tnode->info
  1450.     movea.l    _FSFib,a3        ;a3 = FSFib
  1451.  
  1452.     move.l    fib_Size(a3),nd_filesize(a2) ;tinfo->filesize = FSFib->fib_Size
  1453.     move.l    fib_DateStamp+0(a3),nd_days(a2) ;tinfo->day = FSFib->fib_DateStamp.ds_Days
  1454.     move.l    fib_DateStamp+4(a3),nd_minutes(a2)
  1455.     move.l    fib_DateStamp+8(a3),nd_ticks(a2)
  1456.  
  1457.     pea    fib_DateStamp(a3)
  1458.     jsr    _FibFileDate
  1459.     addq.w    #4,sp
  1460.  
  1461.     movea.l    d0,a1
  1462.     lea    nd_alphadata(a2),a0    ;a0 = tinfo->alphadata
  1463.     jsr    astrcpy            ;a0 = astrcpy(&tinfo->alphadata[0], FibFileDate(&FSFib->DateStamp))
  1464.  
  1465.     tst.l    fib_DirEntryType(a3)    ;If < 0 it is a file
  1466.      bge.s    ffnisdir        ;>= 0, it is a dir
  1467.  
  1468. ffnisfile:
  1469.     move.w    #1,nd_filetype(a2)    ;tinfo->filetype = 1
  1470.     move.w    #FPEN,nd_textcolor(a2)    ;tinfo->textcolor = FPEN
  1471.  
  1472.     move.l    a0,-(sp)
  1473.     move.l    fib_Size(a3),-(sp)
  1474.     pea    _FSSizeFmtStr
  1475.     move.l    a0,-(sp)
  1476.     jsr    _sprintf        ;sprintf(a0, "%8ld ", FSFib->fib_Size)
  1477.     lea    12(sp),sp
  1478.     movea.l    (sp)+,a0
  1479.     adda.w    #9,a0            ;Skip filesize part of message
  1480.     bra.s    ffnsetname
  1481.  
  1482. ffnisdir:
  1483.     move.w    #2,nd_filetype(a2)    ;tinfo->filetype = 2
  1484.     move.w    #DPEN,nd_textcolor(a2)    ;tinfo->textcolor = DPEN
  1485.  
  1486.     lea    _FSDirFmtStr,a1
  1487.     jsr    astrcpy            ;astrcpy(dest, FSDirFmtStr)
  1488.  
  1489. ffnsetname:
  1490.     moveq    #0,d0
  1491.     lea    fib_FileName(a3),a1    ;a1 = FSFib->fib_FileName
  1492. 1$    move.b    (a1)+,d1
  1493.      beq.s    2$            ;Hit null, see if we need to pad
  1494.     move.b    d1,(a0)+        ;copy a char, till null
  1495.     addq.w    #1,d0            ;i++
  1496.     cmpi.w    #30,d0            ;Max chars yet?
  1497.      bcs    1$
  1498.  
  1499. 2$    move.w    d0,nd_namelength(a2)    ;tinfo->namelength = i
  1500.     move.b    #' ',d1
  1501.     bra.s    4$            ;Append spaces till 30 chars
  1502. 3$    move.b    d1,(a0)+
  1503.     addq.w    #1,d0
  1504. 4$    cmpi.w    #30,d0
  1505.      bcs    3$
  1506.  
  1507.     clr.b    (a0)            ;Null terminate at 31st char
  1508.  
  1509. ffnsetshow:
  1510.     movea.l    ffnnode(sp),a2
  1511.     moveq    #1,d0
  1512.     movea.l    a2,a0            ;a0 = tnode
  1513.     jsr    _FSValidateEntry    ;FSValidateEntry(tnode, 1)
  1514.  
  1515. ; Now insert the node into list according to sort type
  1516. ffninsert:
  1517.     movea.l    _fnList,a3
  1518.     movea.l    MLH_HEAD(a3),a3        ;a3 = fnList->lh_Head
  1519.  
  1520.     movea.l    _FSReq,a0
  1521.     move.w    fs_sorttype(a0),d2    ;d0 = FSReq->sorttype
  1522.  
  1523. 1$
  1524.     tst.l    fn_Node+MLN_SUCC(a3)    ;Is this the end of the list?
  1525.      beq.s    2$            ;Nope, insert it here
  1526.  
  1527.     move.l    fn_info(a3),a1        ;Push existing node->info
  1528.     move.l    fn_info(a2),a0        ;Push tnode->info
  1529.     move.w    d2,d0            ;Push sort type
  1530.     jsr    _CompareNodes        ;Compare info's according to sort type
  1531.     tst.w    d0            ;Is a0 > a1?
  1532.      beq.s    2$            ;nope, found insertion point
  1533.     movea.l    fn_Node+MLN_SUCC(a3),a3    ;oldnode = oldnode->next
  1534.     bra    1$            ;Nope, keep looking
  1535.  
  1536. 2$
  1537.     movea.l    _fnList,a0
  1538.     movea.l    a2,a1
  1539.     move.l    fn_Node+MLN_PRED(a3),a2
  1540.     SYS    Insert,4
  1541.  
  1542. ffndone:
  1543.     movem.l    (sp)+,d2/a2-a3/a6
  1544.     rts
  1545.  
  1546.  
  1547. ; VOID FSValidateEntry(tnode, mode)
  1548. ;            a0     d0
  1549.  
  1550.     XDEF    _FSValidateEntry
  1551. _FSValidateEntry:
  1552.     movem.l    d2-d3/a2,-(sp)
  1553.  
  1554. ; See if the Acceptor likes this node name
  1555.     move.l    d0,d3            ;d3 = mode
  1556.     movea.l    a0,a2            ;a2 = tnode
  1557.     move.l    a2,-(sp)
  1558.     jsr    _FSAcceptEntry        ;if (FSAcceptEntry(tnode) == 0)
  1559.     addq.w    #4,sp
  1560.     tst.w    d0
  1561.      bne.s    1$
  1562.  
  1563. ; Don't display this node
  1564.     movea.l    fn_info(a2),a0
  1565.     clr.w    nd_showit(a0)        ;tnode->info->showit = 0;
  1566.     move.w    #-1,fn_idnum(a2)    ;tnode->idnum = -1
  1567.     bra.s    4$            ;And return
  1568.  
  1569. ; Accept this node for display
  1570. 1$    movea.l    fn_info(a2),a0
  1571.     move.w    #1,nd_showit(a0)    ;else tnode->info->showit = 1;
  1572.  
  1573.     moveq    #0,d2
  1574.     move.w    _fsnumentries,d2    ;Grab entry number for this node
  1575.      bne.s    2$            ;Not first entry
  1576.     move.l    a2,_topfin        ;topnode = tnode, first visible node
  1577. 2$
  1578.     move.w    d2,fn_idnum(a2)        ;tnode->idnum = fsnumentries
  1579.     addq.w    #1,_fsnumentries    ;fsnumentries++, one more visible entry
  1580.     clr.w    _fsneedshow     ;fsneedshow = 0, needs sorting
  1581.  
  1582. ; If we haven't filled display area, show this entry
  1583.     cmpi.w    #10,d2            ;> 10 entries already?
  1584.      bcc.s    3$            ;Yep, just set the knob
  1585.  
  1586.     lea    _FSFileNodes,a0
  1587.     move.w    d2,d0            ;Grab entry number
  1588.     lsl.w    #2,d0            ;Convert to long table offset
  1589.     move.l    a2,0(a0,d0.w)        ;FSFileNodes[fsnumentries] = tnode
  1590.  
  1591.     move.l    d2,-(sp)
  1592.     jsr    _FSEnableFGad        ;FSEnableFGad(fsnumentries)
  1593.     addq.w    #4,sp
  1594.     bra.s    4$            ;Skip setting knob, it is still full size
  1595.  
  1596. 3$
  1597.     tst.w    d3            ;Want slide update?
  1598.      beq.s    4$            ;Nope
  1599.  
  1600.     btst.b    #7,_FSSlideGad+gg_Flags+1 ;User has slide gadget in use?
  1601.      bne.s    4$            ;Yes, don't refresh it while in use
  1602.  
  1603. ; Calc new knob size and refresh
  1604.     btst.l    #0,d2            ;(idnum % 2) == 0?
  1605.      beq.s    4$            ;Yep, don't reset on even values
  1606.     jsr    _FSResetKnob
  1607.  
  1608. 4$
  1609.     movem.l    (sp)+,d2-d3/a2
  1610.     rts
  1611.  
  1612.  
  1613. ; Update FileTexts list, redisplay
  1614. ; Renumber list, find new topfin
  1615.  
  1616.     XDEF    _FSUpdateSort
  1617. _FSUpdateSort:
  1618.     move.w    _fsneedshow,d0
  1619.      blt.s    3$
  1620.     move.w    _fsnumentries,d1
  1621.      beq.s    2$
  1622.     subi.w    #10,d1            ;Less max number of visible files
  1623.     move.w    _FSSlideProp+4,d0    ;Grab current vpot
  1624.     mulu    d1,d0            ;Times position percentage
  1625.     addi.l    #32768,d0
  1626.     clr.w    d0
  1627.     swap    d0
  1628.     jsr    _FSResetNumEntries
  1629.     jsr    _FSSetFileGads
  1630. 2$
  1631.     move.w    #-1,_fsneedshow
  1632.     moveq    #0,d0
  1633.  
  1634. 3$    tst.w    d0
  1635.     rts
  1636.  
  1637.  
  1638. ; VOID FSResetNumEntrys(idnum)
  1639. ;            d0:16
  1640.  
  1641.     XDEF    _FSResetNumEntries
  1642. _FSResetNumEntries:
  1643.     move.l    a2,-(sp)
  1644.  
  1645.     movea.l    _fnList,a2        ;Grab List
  1646.     movea.l    MLH_HEAD(a2),a2        ;Head of list
  1647.  
  1648.  
  1649.     moveq    #0,d1            ;i = 0
  1650.  
  1651. 1$    tst.l    fn_Node+MLN_SUCC(a2)    ;End of list?
  1652.      beq.s    5$
  1653.     movea.l    fn_info(a2),a0        ;a0 = tnode->info
  1654.     tst.w    nd_showit(a0)        ;Visible?
  1655.      bne.s    2$            ;Yep
  1656.     move.w    #-1,fn_idnum(a2)    ;Else tnode->idnum = -1
  1657.     bra.s    4$            ;Next node
  1658. 2$    move.w    d1,fn_idnum(a2)        ;tnode->idnum = i
  1659.     cmp.w    d1,d0            ;if (idnum == oldidnum)
  1660.      bne.s    3$
  1661.     move.l    a2,_topfin        ; topfin = tnode;
  1662. 3$
  1663.     addq.w    #1,d1            ;i++
  1664. 4$
  1665.     movea.l    fn_Node+MLN_SUCC(a2),a2    ;tnode = tnode->fn_Node.mln_Succ
  1666.     bra    1$            ; Check next node
  1667.  
  1668. 5$
  1669.     move.w    d1,_fsnumentries    ;Update number of entries
  1670.  
  1671.     movea.l    (sp)+,a2
  1672.     rts
  1673.  
  1674.  
  1675. ; LONG FSAcceptEntry(struct file_node *tnode);
  1676. ; Decide whether given tnode is displayable.
  1677. ; Return 0L for ignore this node, 1L for valid node.
  1678.  
  1679. aftnode    EQU    8
  1680. aftname    EQU    -48
  1681.  
  1682.     XDEF    _FSAcceptEntry
  1683. _FSAcceptEntry:
  1684.     link    a5,#aftname
  1685.     movem.l    a2-a3,-(sp)
  1686.  
  1687.     movea.l    aftnode(a5),a2        ;Grab tnode
  1688.     movea.l    fn_info(a2),a3        ;Grab tnode->info
  1689.  
  1690. ; Copy tnode->info->alphadata name section to stack, null terminate
  1691.     move.w    nd_namelength(a3),d0    ;Push tinfo->namelength
  1692.     lea    nd_alphadata+26(a3),a1    ;Push tinfo->alphadata + 26
  1693.     lea    aftname(a5),a0        ;Push destination
  1694.     jsr    astrncpy        ;Copy and null terminate
  1695.  
  1696. ; If there is a special match function defined, use that...
  1697.     movea.l    _FSReq,a0
  1698.     tst.l    fs_matchfunc(a0)    ;If FSReq->matchfunc != 0
  1699.      beq.s    1$
  1700.     move.l    aftnode(a5),-(sp)
  1701.     pea    aftname(a5)
  1702.     move.l    _FSReq,-(sp)
  1703.     move.l    fs_matchfunc(a0),a0
  1704.     jsr    (a0)            ;return((FSReq->matchfunc)(FSReq, name, tnode)
  1705.     lea    12(sp),sp
  1706.     bra.s    aftdone
  1707.  
  1708. ; Otherwise use built-in acceptor routine
  1709. 1$    cmpi.w    #2,nd_filetype(a3)    ;Is tinfo->filetype == 2? (a directory)
  1710.      beq.s    aftisdir        ;Yep, we need it in list
  1711.  
  1712. ; Check file name against patterns
  1713.     btst.b    #6,_fsflags+1    ;Want dirs only?
  1714.      bne.s  aftwrongpat        ;Yep, ignore all files
  1715.  
  1716.     pea    _FSIgnorePat    ;See if it matches the ignore text
  1717.     pea    aftname(a5)
  1718.     jsr    _wildmatch
  1719.     addq.w    #8,sp
  1720.     tst.w    d0            ;Did it match the ignore text?
  1721.      bne.s    aftwrongpat        ;Yep, ignore this file
  1722.  
  1723.     move.l    _FSPatternInfo,-(sp) ;See if it matches desired pattern
  1724.     pea    aftname(a5)
  1725.     jsr    _wildmatch
  1726.     addq.w    #8,sp
  1727.     tst.w    d0            ;Did it match?
  1728.      beq.s    aftwrongpat        ;Nope, skip it
  1729.     bra.s    aftgoodpat        ;Else accept this file
  1730.  
  1731. aftisdir:
  1732.     btst.b    #5,_fsflags+1    ;This is a dir, want files only?
  1733.      bne.s    aftwrongpat        ;Yep, ignore this dir
  1734.  
  1735. aftgoodpat:
  1736.     moveq    #1,d0            ;Accept this entry
  1737.     bra.s    aftdone
  1738.  
  1739. aftwrongpat:
  1740.     moveq    #0,d0            ;Ignore this entry
  1741.  
  1742. aftdone:
  1743.     movem.l    (sp)+,a2-a3
  1744.     unlk    a5
  1745.     rts
  1746.  
  1747.  
  1748. ; VOID FSMatchPattern(VOID);
  1749. ; Called when path or pattern has changed - rematch all entries
  1750. ; against the new pattern, display entries that match.
  1751.  
  1752.     XDEF    _FSMatchPattern
  1753. _FSMatchPattern:
  1754.     movem.l    d4/a2-a3/a6,-(sp)
  1755.  
  1756. ; Pattern match list against new pattern, flag unwanted names
  1757.     movea.l    _FSPatternInfo,a0     ;Grab pattern
  1758.     tst.b    (a0)            ;Null pattern text?
  1759.      bne.s    mnpnotnop        ;Nope, process it
  1760.  
  1761.     move.b    #'*',(a0)+        ;Otherwise put back wildstar
  1762.     clr.b    (a0)            ;Null terminate
  1763.     lea    _FSPatternInfo,a0    ;Grab stringinfo
  1764.     move.w    #1,8(a0)        ;FSPatternInfo.BufferPos = 1;
  1765.  
  1766.     lea    _FSPatternGad,a0
  1767.     movea.l    _FSWin,a1
  1768.     suba.l    a2,a2
  1769.     moveq    #1,d0
  1770.     SYS    RefreshGList,_IntuitionBase ;Refresh pattern text gadget
  1771.  
  1772.     move.l    _FSWin,-(sp)
  1773.     pea    _FSPatternGad
  1774.     jsr    _MyActivateGad        ;MyActivateGad(&FSPatternGad, FSWin)
  1775.     addq.w    #8,sp
  1776.     bra.s    mnpdone            ;Make the user type something else in
  1777.  
  1778. mnpnotnop:
  1779.     movea.l    _fnList,a0
  1780.     move.l    MLH_HEAD(a0),a0
  1781.     tst.l    fn_Node+MLN_SUCC(a0)    ;Do we have any files to match?
  1782.      beq.s    mnpdone            ;Nope, nothing to do
  1783.  
  1784. ; Reset knob to full height, zero position
  1785.     clr.w    _fsnumentries    ;Clear fsnumentries count
  1786.     clr.w    _fsvposition
  1787.     move.w    #$ffff,_fsvheight
  1788.     jsr    _FSSetKnob        ;Show new knob
  1789.  
  1790. ; Disable all file "gadgets"
  1791.     jsr    _FSDisableAllFGads
  1792.  
  1793. ; Scan list, enable/flag entries that match new pattern
  1794.     movea.l    _fnList,a2        ;tnode = fnList
  1795.     movea.l    MLH_HEAD(a2),a2        ;tnode = head node
  1796.     clr.l    _topfin        ;Clear out top/bot display pointers
  1797. 1$
  1798.     tst.l    fn_Node+MLN_SUCC(a2)    ;End of list?
  1799.      beq.s    2$
  1800.  
  1801.     moveq    #0,d0
  1802.     movea.l    a2,a0
  1803.     jsr    _FSValidateEntry    ;FSValidateEntry(tnode, 0)
  1804.     movea.l    fn_Node+MLN_SUCC(a2),a2    ;tnode = tnode->fn_Node.mln_Succ
  1805.     bra    1$            ;Nope, process this one too
  1806. 2$
  1807.     move.w    #-1,_fsneedshow    ;Clear reshow/sort flag, list valid
  1808.     cmpi.w    #10,_fsnumentries    ;Found some entries?
  1809.      bls.s    mnpsettitle        ;Yep, skip setting knob again
  1810.     jsr    _FSResetKnob        ;Show new knob size
  1811.  
  1812. mnpsettitle:
  1813.     tst.w    _fsnumentries    ;Got any matches to pattern?
  1814.      bne.s    mnpmatchedsome        ;Yep
  1815.  
  1816.     move.w    #24,_fstitstatus    ;"Nothing matched PATTERN"
  1817.     bra.s    mnpnewtit
  1818.  
  1819. mnpmatchedsome:
  1820.     move.w    #29,_fstitstatus    ;"Select a file..."
  1821.  
  1822. mnpnewtit:
  1823.     jsr    _FSWinTitle        ;Show final title status
  1824.  
  1825. mnpdone:
  1826.     movem.l    (sp)+,d4/a2-a3/a6
  1827.     rts
  1828.  
  1829.  
  1830. ; VOID ConcatPathString(VOID)
  1831. ;
  1832. ;  If the file text is non-NULL, concat path text and file text,
  1833. ; set global exit flag to show user selected a filename.
  1834.  
  1835.     XDEF    _ConcatPathString
  1836. _ConcatPathString:
  1837. ; Try to add path prefix
  1838.     move.l    _FSFileInfo,-(sp)
  1839.     move.l    _FSPathInfo,-(sp)
  1840.     movea.l    _FSReq,a0        ;Grab final pathtext
  1841.     movea.l    fs_fullname(a0),a0
  1842.     move.l    a0,-(sp)
  1843.     jsr    _ConcatDirFile        ;ConcatDirFile(FSReq->fullname, FSPathInfo->Buffer, FSFileInfo->Buffer)
  1844.     lea    12(sp),sp
  1845.  
  1846. ; Did the user select a filename yet?
  1847.     movea.l    _FSFileInfo,a0
  1848.     tst.b    (a0)            ;First byte of name null?
  1849.      bne.s    1$            ;Nope, must be okay
  1850.     btst.b    #2,_fsflags+1    ;(FSFlags & FS_NO_STRING_OKAY) == 0?
  1851.      beq.s    2$            ;Yep, user can't exit till something is entered
  1852. 1$
  1853. ; Flag main loop to exit
  1854.     move.w    #1,_FSDone
  1855. 2$
  1856.     rts
  1857.  
  1858.  
  1859. ; VOID __stdargs ConcatDirFile(BYTE *, BYTE *, BYTE *)
  1860.  
  1861.     XDEF    _ConcatDirFile
  1862. _ConcatDirFile:
  1863.     movem.l    4(sp),a0-a1        ;grab dest, dirname
  1864.     tst.b    (a1)            ;Is there a dirname here?
  1865.      beq.s    1$            ;Nope
  1866.     jsr    astrcpy            ;astrcpy(dest, dirname)
  1867.     movea.l    12(sp),a1        ;grab filename
  1868.     tst.b    (a1)            ;Is there a filename?
  1869.      beq.s    2$            ;Nope, don't concat a slash
  1870.     move.b    -1(a0),d0        ;d0 = dest[strlen(dest - 1)]
  1871.     cmpi.b    #':',d0            ;Already has a colon?
  1872.      beq.s    1$            ;Yep
  1873.     cmpi.b    #'/',d0            ;Already has a slash?
  1874.      beq.s    1$            ;Yep
  1875.     move.b    #'/',(a0)+        ;Append a slash
  1876.     clr.b    (a0)            ;Terminate
  1877. 1$
  1878.     movea.l    12(sp),a1
  1879.     jsr    astrcpy            ;astrcpy(dest, name)
  1880. 2$
  1881.     rts
  1882.  
  1883.  
  1884. ; VOID FSDoSlideGadget(VOID)
  1885. ;
  1886. ;  Process the current slide gadget position, scroll file entries
  1887. ; to match current position.
  1888.  
  1889.     XDEF    _FSDoSlideGadget
  1890. _FSDoSlideGadget:
  1891.     movem.l    d4-d5,-(sp)
  1892.  
  1893.     jsr    _FSUpdateSort
  1894.      beq    dsgdone
  1895.  
  1896.     cmpi.w    #10,_fsnumentries    ;Do we have less than 10 entries?
  1897.      blt    dsgdone            ;Yep, can't move anyhow
  1898.  
  1899.     moveq    #0,d0
  1900.     move.w    _FSSlideProp+4,d0    ;Grab new vpot
  1901.     cmp.w    _fsvposition,d0     ;Has it moved?
  1902.      beq    dsgdone            ;Nope
  1903.  
  1904.     move.w d0,_fsvposition     ;Otherwise update position
  1905.  
  1906.     move.w    _fsnumentries,d4    ;Grab number of entries
  1907.     subi.w    #10,d4            ;Less max number of visible files
  1908.     mulu    d0,d4            ;Times position percentage
  1909.     addi.l    #32768,d4
  1910.     clr.w    d4
  1911.     swap    d4
  1912.  
  1913.     movea.l    _topfin,a0        ;Grab top node
  1914.     cmp.w    fn_idnum(a0),d4        ;Is node->idnum the same as newpos?
  1915.      beq.s    dsgdone            ;Yep, don't have to move it
  1916.      bcc.s    dsgscrup        ;newpos is lower, scroll up
  1917.  
  1918.  
  1919. ; Scroll Down
  1920.  
  1921.     move.w    fn_idnum(a0),d0        ;Grab topfin->idnum
  1922.     sub.w    d4,d0            ;i = idnum - newpos
  1923.     cmpi.w    #8,d0            ;Need to scroll more than 8?
  1924.      ble.s    dsgssdwn        ;Nope, use slow scroll
  1925.  
  1926. dsgdwn1:
  1927.     cmp.w    fn_idnum(a0),d4        ;Is topfin->idnum == newpos yet?
  1928.      beq.s    dsgredo            ;Yep, we are done
  1929.  
  1930. dsgpretop:
  1931.     movea.l    fn_Node+MLN_PRED(a0),a0    ;topfin = topfin->fn_Node.mln_Pred
  1932.     tst.w    fn_idnum(a0)        ;Is this idnum >= 0?
  1933.      blt.s    dsgpretop        ;Nope, keep looking
  1934.     bra.s    dsgdwn1            ;Check this new position
  1935.  
  1936. dsgssdwn:
  1937.     move.l    d0,-(sp)
  1938.     jsr    _FSScrollDownGads    ;Scroll entries down d5 times
  1939.     addq.w    #4,sp
  1940.     bra.s    dsgdone
  1941.  
  1942.  
  1943. ; Scroll Up
  1944.  
  1945. dsgscrup:
  1946.     move.w    d4,d5            ;Grab newpos
  1947.     sub.w    fn_idnum(a0),d5        ;i = newpos - node->idnum
  1948.     cmpi.w    #8,d5            ;i > 8?
  1949.      ble.s    dsgssup            ;Nope, use slow scroll
  1950.  
  1951. dsgmvup1:
  1952.     cmp.w    fn_idnum(a0),d4        ;Is topfin->idnum == newpos yet?
  1953.      beq.s    dsgredo            ;Yep, we are done
  1954.  
  1955. dsgnxttop:
  1956.     movea.l    fn_Node+MLN_SUCC(a0),a0    ;topfin = topfin->fn_Node.mln_Succ
  1957.     tst.w    fn_idnum(a0)        ;Is this a valid entry?
  1958.      blt.s    dsgnxttop        ;Nope, move on
  1959.     bra.s    dsgmvup1
  1960.  
  1961. dsgredo:
  1962.     move.l    a0,_topfin        ;Set new top and bottom
  1963.     jsr    _FSSetFileGads        ;Redraw all the file entries
  1964.     bra.s    dsgdone            ;We're done
  1965.  
  1966. dsgssup:
  1967.     move.l    d5,-(sp)
  1968.     jsr    _FSScrollUpGads        ;Scroll the entries up d5 times
  1969.     addq.w    #4,sp
  1970.  
  1971. dsgdone:
  1972.     movem.l    (sp)+,d4-d5
  1973.     rts
  1974.  
  1975.  
  1976. ; VOID FSStartScrollGad(gadcode)
  1977. ;   ULONG gadcode;
  1978. ; Given Gadget ID code, respond to first user click on a arrow gadget.
  1979. ; Reset the timer.device so that .25 seconds delay occurs before
  1980. ; the autorepeat kicks in.
  1981.  
  1982.     XDEF    _FSStartScrollGad
  1983. _FSStartScrollGad:
  1984.     move.w    6(sp),d0    ;Grab gadget code
  1985.     subi.w    #33,d0        ;Slide gad
  1986.      bne.s    1$
  1987.     jsr    _FSDoSlideGadget
  1988.     clr.w    _FSCountDown
  1989.     rts
  1990.  
  1991. 1$
  1992.     subi.w    #7,d0        ;33+7=40, UpGad
  1993.      bne.s    2$
  1994.     pea    1
  1995. 11$    jsr    _FSScrollFileGads
  1996.     addq.w    #4,sp
  1997.     bra.s    ssgdone
  1998. 2$
  1999.     subq.w    #1,d0        ;33+7+1=41, DownGad
  2000.      bne.s    3$
  2001.     pea    0
  2002.     bra    11$
  2003. 3$
  2004.     subq.w    #1,d0        ;33+7+2=42, UpDev
  2005.      bne.s    4$
  2006.     pea    1
  2007. 33$    jsr    _FSScrollDevGads
  2008.     addq.w    #4,sp
  2009.     bra.s    ssgdone
  2010. 4$
  2011.     subq.w    #1,d0        ;33+7+3=43, DownDev
  2012.      bne.s    ssgrts
  2013.     pea    0
  2014.     bra    33$
  2015.  
  2016. ssgdone:
  2017.     move.w    #4,_FSCountDown
  2018. ssgrts:
  2019.     rts
  2020.  
  2021.  
  2022. ; FSScrollFileGads(direction)
  2023. ;   BOOL direction;
  2024. ;
  2025. ; Scroll the file entries up or down by 1
  2026. ; if (direction == 0)
  2027. ;   scrollup;
  2028. ; else
  2029. ;   scrolldown;
  2030.  
  2031.     XDEF    _FSScrollFileGads
  2032. _FSScrollFileGads:
  2033.  
  2034. ;if (fsnumentries > 10)
  2035.     cmpi.w    #10,_fsnumentries    ;Less than 10 entries?
  2036.      ble.s    sfgdone            ;Yep, can't scroll anyhow
  2037.  
  2038. ;if (direction)
  2039. ;  FSScrollDownGads(1);
  2040.     tst.w    6(sp)            ;ScrollDown?
  2041.      beq.s    sfgup            ;Nope, scroll up
  2042.     pea    1
  2043.     jsr    _FSScrollDownGads
  2044.     addq.w    #4,sp
  2045.     bra.s    sfgpos
  2046.  
  2047. sfgup:
  2048. ;FSScrollUpGads(1)
  2049.     pea    1
  2050.     jsr    _FSScrollUpGads
  2051.     addq.w    #4,sp
  2052.  
  2053. sfgpos:
  2054. ; Reset the slide knob position the display movement
  2055.     jsr    _FSSetKnobPos
  2056.     jsr    _FSSetKnob        ;Set new knob position
  2057.  
  2058. sfgdone:
  2059.     rts
  2060.  
  2061.  
  2062. ; FSScrollUpGads(count)
  2063. ;  LONG count;
  2064. ;
  2065. ;  Single-step scroll the file entries up count times.
  2066.  
  2067.     XDEF    _FSScrollUpGads
  2068. _FSScrollUpGads:
  2069.     link    a5,#0
  2070.     movem.l    d2-d7/a2/a6,-(sp)
  2071.  
  2072.     jsr    _FSUpdateSort
  2073.      beq.s    sugdone
  2074.  
  2075.     movea.l    _FSRPort,a2
  2076.  
  2077. ;for (i = 0; i < count; i++)
  2078.     moveq    #0,d7
  2079.     bra.s    sugchk1
  2080.  
  2081. sugloop1:
  2082. ; If the bottom entry is not the last entry, scroll it up
  2083.     movea.l    _topfin,a0        ;Grab top visible node
  2084.     move.w    fn_idnum(a0),d0        ;Grab id number
  2085.     addi.w    #11,d0            ;Plus 11
  2086.     cmp.w    _fsnumentries,d0    ;Compare to last known entry
  2087.      bgt.s    sugdone            ;Yep, can't scroll up any more
  2088.  
  2089. ; Bump the top pointer down the list to the next visible entry
  2090.     movea.l    _topfin,a0
  2091. 1$    move.l    fn_Node+MLN_SUCC(a0),a0    ;topfin = topfin->fn_Node.mln_Succ
  2092.     tst.w    fn_idnum(a0)        ;while (topfin->idnum < 0)
  2093.      blt    1$            ;Not a valid entry
  2094.     move.l    a0,_topfin        ;Here's our new top entry node
  2095.  
  2096. ; Now reassign the visible file gadget array to the new node list
  2097.     jsr    _FSAssignNodes
  2098.  
  2099. ; Display new file entries and redraw borders
  2100. ;ClipBlit(rp, 9L, 24L, rp, 9L, 13L, 447L, 96L, 0xc0L);
  2101.     movea.l    a2,a0
  2102.     moveq    #9,d0
  2103.     moveq    #24,d1
  2104.     movea.l    a2,a1
  2105.     moveq    #9,d2
  2106.     moveq    #13,d3
  2107.     move.l    #447,d4
  2108.     moveq    #96,d5
  2109.     move.l    #$0c0,d6
  2110.     SYS    ClipBlit,_GfxBase
  2111.  
  2112. ;FSEnableFGad(9);
  2113.     move.l    #9,-(sp)
  2114.     jsr    _FSEnableFGad        ;Now draw the new gadget at bottom
  2115.     addq.w    #4,sp
  2116.  
  2117.     addq.w    #1,d7            ;Bump scroll count
  2118.  
  2119. sugchk1:
  2120.     cmp.w    10(a5),d7        ;Have we scrolled enough?
  2121.      blt    sugloop1        ;Nope, do again
  2122.  
  2123. sugdone:
  2124.     movem.l    (sp)+,d2-d7/a2/a6
  2125.     unlk    a5
  2126.     rts
  2127.  
  2128.  
  2129. ; FSScrollDownGads(count)
  2130. ;   LONG count;
  2131. ;
  2132. ;  Single-step scroll the file entries down count times.
  2133.  
  2134.     XDEF    _FSScrollDownGads
  2135. _FSScrollDownGads:
  2136.     link    a5,#0
  2137.     movem.l    d2-d7/a2/a6,-(sp)
  2138.  
  2139.     jsr    _FSUpdateSort
  2140.      beq.s    sdgdone
  2141.  
  2142.     movea.l    _FSRPort,a2
  2143.  
  2144. ;for (i = 0; i < count; i++)
  2145.     moveq    #0,d7
  2146.     bra.s    sdgchk1
  2147.  
  2148. sdgloop1:
  2149. ;If the top entry is not the first entry, scroll it down
  2150.     movea.l    _topfin,a0        ;Grab top node
  2151.     tst.w    fn_idnum(a0)        ;idnum == 0?
  2152.      beq.s    sdgdone            ;Yep, can't scroll down any more
  2153.  
  2154. ; Bump the top and bottom entry pointers down the list
  2155. 1$    movea.l    fn_Node+MLN_PRED(a0),a0    ;topfin = topfin->fn_Node.mln_Pred
  2156.     tst.w    fn_idnum(a0)        ;while (topfin->idnum < 0)
  2157.      blt    1$
  2158.     move.l    a0,_topfin        ;New topfin
  2159.  
  2160. ; Now reassign the visible file gadget array to the new node list
  2161.     jsr    _FSAssignNodes
  2162.  
  2163. ; Display new file entries and redraw borders
  2164. ;ClipBlit(rp, 9L, 13L, rp, 9L, 24L, 447L, 96L, 0xc0L)
  2165.     movea.l    a2,a0
  2166.     moveq    #9,d0
  2167.     moveq    #13,d1
  2168.     movea.l    a2,a1
  2169.     moveq    #9,d2
  2170.     moveq    #24,d3
  2171.     move.l    #447,d4
  2172.     moveq    #96,d5
  2173.     move.l    #$0c0,d6
  2174.     SYS    ClipBlit,_GfxBase
  2175.  
  2176. ;FSEnableFGad(0);
  2177.     pea    0
  2178.     jsr    _FSEnableFGad        ;Display the only new "gadget"
  2179.     addq.w    #4,sp
  2180.  
  2181.     addq.w    #1,d7            ;Bump scroll count
  2182.  
  2183. sdgchk1:
  2184.     cmp.w    10(a5),d7        ;Have we scrolled enough?
  2185.      blt    sdgloop1        ;Nope, do again
  2186.  
  2187. sdgdone:
  2188.     movem.l    (sp)+,d2-d7/a2/a6
  2189.     unlk    a5
  2190.     rts
  2191.  
  2192.  
  2193. ; VOID FSAssignNodes(VOID)
  2194.  
  2195.     XDEF    _FSAssignNodes
  2196. _FSAssignNodes:
  2197.     movem.l    a2-a3,-(sp)
  2198.  
  2199. ;for (tnode = topfin, i = 0; ;tnode = tnode->next)
  2200.     lea    _FSFileNodes,a3    ;Grab base address of array of filegadgets
  2201.     movea.l    _topfin,a2        ;Grab our top visible filenode
  2202.     moveq    #10,d0            ;Fill 10 gadgets max
  2203. ran1:
  2204.     tst.l    fn_Node+MLN_SUCC(a2)    ;Succ == 0?
  2205.      beq.s    ragdone            ;Ran out of list entries
  2206.  
  2207. ;if (tnode->idnum >= 0)
  2208.     tst.w    fn_idnum(a2)        ;Is this name "visible"?
  2209.      blt.s    ragchkbot        ;Nope, skip it
  2210.     move.l    a2,(a3)+        ;FSFileNodes[i] = tnode
  2211.     subq.w    #1,d0            ;One less slot available
  2212.      beq.s    ragdone            ;Filled all the slots, exit loop
  2213.  
  2214. ragchkbot:
  2215.     movea.l    fn_Node+MLN_SUCC(a2),a2
  2216.     bra    ran1            ;check next node
  2217.  
  2218. ragdone:
  2219.     movem.l    (sp)+,a2-a3
  2220.     rts
  2221.  
  2222.  
  2223. ; VOID __stdargs FSDoFileGad(Ypos)
  2224. ;   LONG Ypos;
  2225. ;
  2226. ;  Based on the mouse's Ypos passed, select file entry that user clicked.
  2227.  
  2228.     XDEF    _FSDoFileGad
  2229. _FSDoFileGad:
  2230.     link    a5,#0
  2231.     movem.l    d2-d4/a2-a3/a6,-(sp)
  2232.  
  2233.     moveq    #0,d4
  2234.     move.w    10(a5),d4        ;Grab gadget y position
  2235.     subi.w    #12,d4            ;Less 12 (top edge of first entry)
  2236.     divu    #11,d4            ; divided by 11 (height of each entry)
  2237.     ext.l    d4            ;Blow remainder, this is our entry number
  2238.  
  2239.     move.w    d4,d0
  2240.     lsl.w    #2,d0            ;Convert to long offset
  2241.     lea    _FSFileNodes,a2    ;Grab base address of visible node_datas
  2242.     movea.l    0(a2,d0.w),a3        ;Grab FSFileNodes[gadg_num]
  2243.     cmpa.l    #0,a3
  2244.      beq    dfgdone            ;If zero, not a active "gadget" slot
  2245.  
  2246. ;strncpy(FSwstr, tinfo->alphadata + 26L, tinfo->namelength)
  2247.     movea.l    fn_info(a3),a3        ;tinfo = tnode->info
  2248.     lea    _FSwstr,a2        ;Grab address of worktext
  2249.     move.w    nd_namelength(a3),d0    ;Push tinfo->namelength
  2250.     lea    nd_alphadata+26(a3),a1    ;Push tinfo->alphadata + 26
  2251.     movea.l    a2,a0            ;Push dest text
  2252.     jsr    astrncpy        ;strncpy(FSwstr, filename, namelength)
  2253.  
  2254. ;if (tinfo->filetype == 1)
  2255.     cmpi.w    #1,nd_filetype(a3)    ;Did user click on a filename?
  2256.      bne.s    dfgnotfile        ;Nope, must be a dir
  2257.  
  2258. ;if ( strcmp(FSFileInfo.Buffer, FSwstr) )
  2259.     movea.l    a2,a1            ;Push FSwstr
  2260.     movea.l    _FSFileInfo,a0    ;Push address of filebuffer
  2261.     jsr    astrcmp
  2262.     tst.w    d0            ;Is this the same as what we already have?
  2263.      beq.s    dfgnsname        ;Yep, see if it was double-clicked
  2264.  
  2265. ;strcpy(FSFileInfo.Buffer, FSwstr)
  2266.     movea.l    a2,a1
  2267.     movea.l    _FSFileInfo,a0
  2268.     jsr    astrcpy            ;Otherwise copy new filename to filebuffer
  2269.  
  2270.     lea    _FSFileGad,a0     ;And refresh filename text gadget
  2271.     movea.l    _FSWin,a1
  2272.     suba.l    a2,a2
  2273.     moveq    #1,d0
  2274.     SYS    RefreshGList,_IntuitionBase
  2275.     bra    dfgfiledone
  2276.  
  2277. dfgnsname:
  2278. ;if ( DoubleClick(fsoldsecs, fsoldmicros, fscursecs, fscurmicros &&
  2279. ; (gadg_num == fsprevgadid) )
  2280. ;  ConcatPathString();
  2281.     btst.b    #0,_fsflags+1    ;FS_NO_DCLICK_EXIT?
  2282.      bne    dfgfiledone        ;Yep, programmer doesn't allow that
  2283.  
  2284.     cmp.w    _fsprevgadid,d4     ;Is it the same gadget?
  2285.      bne    dfgfiledone        ;Nope, can't be a double click
  2286.  
  2287.     move.l    _fsoldsecs,d0
  2288.     move.l    _fsoldmicros,d1
  2289.     move.l    _fscursecs,d2
  2290.     move.l    _fscurmicros,d3
  2291.     SYS    DoubleClick,_IntuitionBase
  2292.     tst.w    d0            ;Is it within click speed parameters?
  2293.      beq.s    dfgfiledone        ;Nope
  2294.  
  2295.     jsr    _ConcatPathString     ;Construct full path text
  2296.     bra.s    dfgdone
  2297.  
  2298. ;Clicked on a DIR
  2299. dfgnotfile:
  2300.     cmpi.w    #1,_fsvirgindir    ;if (virgindir != 1)
  2301.      beq.s    dfgdone         ;Don't concat if we haven't locked dir yet
  2302.  
  2303. ;i = strlen(FSPathInfo.Buffer);
  2304.     move.l    _FSPathInfo,a0
  2305.     jsr    astrlen
  2306.     move.w    d0,d2            ;Length of stuff already in path text
  2307.  
  2308. ;if ( (strlen(FSwstr) + i) < PATHSTRSIZE)
  2309.     movea.l    a2,a0
  2310.     jsr    astrlen
  2311.     add.w    d2,d0
  2312.     cmpi.w    #PATHSTRSIZE-1,d0
  2313.      bge.s    dfgtoodeep         ;Don't append path if no room!
  2314.  
  2315.     move.l    a2,-(sp)
  2316.     move.l    _FSPathInfo,-(sp)
  2317.     move.l    _FSPathInfo,-(sp)
  2318.     jsr    _ConcatDirFile        ;ConcatDirFile(FSPathInfo->Buffer, FSPathInfo->Buffer, FSwstr)
  2319.     lea    12(sp),sp
  2320.  
  2321.     jsr    _FSDirFunc        ;Do FSReq->dirfunc, if there is one
  2322.     tst.w    d0            ;Avoid reading this dir?
  2323.      beq.s    1$            ;Nope, process it
  2324.     move.l    _FSPathInfo,a0
  2325.     clr.b    0(a0,d2.w)        ;Else FSPathInfo->Buffer[oldstrlen] = 0
  2326.     bra.s    dfgdone
  2327. 1$
  2328.     move.w    #1,_fsvirgindir    ;virgindir = 1, read the new directory
  2329.     bra.s    dfgdone
  2330.  
  2331. dfgtoodeep:
  2332.     move.w    #12,_fstitstatus    ;fstitstatus = 12
  2333.     jsr    _FSWinTitle
  2334.     suba.l    a0,a0
  2335.     SYS    DisplayBeep,_IntuitionBase
  2336.     bra.s    dfgdone
  2337.  
  2338. dfgfiledone:
  2339.     jsr    _FSFileFunc        ;Call FSReq->filefunc, if there is one
  2340.  
  2341. dfgdone:
  2342.     move.w    d4,_fsprevgadid     ;fsprevgadid = gadg_num
  2343.     movem.l    (sp)+,d2-d4/a2-a3/a6
  2344.     unlk    a5
  2345.     rts
  2346.  
  2347.  
  2348. ; LONG FSDirFunc(VOID);
  2349. ;  If there is a fsrequest->dirfunc, this routine handles the interface.
  2350.  
  2351.     XDEF    _FSDirFunc
  2352. _FSDirFunc:
  2353.     move.l    d2,-(sp)
  2354.  
  2355.     moveq    #0,d0
  2356.     movea.l    _FSReq,a0        ;Grab our FSRequest struct
  2357.     move.l    fs_dirfunc(a0),d2    ;Is there a user dir function to call?
  2358.      beq.s    1$            ;Nope, that's all we have to do this click!
  2359.  
  2360.     jsr    _ConcatPathString     ;Combine dir/file as fullname for return
  2361.     clr.w    _FSDone        ;Not done though, undo return status
  2362.  
  2363.     move.l    _FSWin,-(sp)
  2364.     move.l    _FSReq,-(sp)
  2365.     movea.l    d2,a0
  2366.     jsr    (a0)            ;d0 = (FSReq->dirfunc)(FSReq, FSWin)
  2367.     addq.w    #8,sp
  2368. 1$
  2369.     move.l    (sp)+,d2
  2370.     rts
  2371.  
  2372.  
  2373. ; VOID FSFileFunc(VOID);
  2374. ;  If there is a fsrequest->filefunc, this routine handles the interface.
  2375.  
  2376.     XDEF    _FSFileFunc
  2377. _FSFileFunc:
  2378.     move.l    d2,-(sp)
  2379.  
  2380.     movea.l    _FSReq,a0        ;Grab our FSRequest struct
  2381.     move.l    fs_filefunc(a0),d2    ;Is there a user file function to call?
  2382.      beq.s    1$            ;Nope, that's all we have to do this click!
  2383.  
  2384.     jsr    _ConcatPathString     ;Combine dir/file as fullname for return
  2385.     clr.w    _FSDone        ;Not done though, undo return status
  2386.  
  2387.     move.l    _FSWin,-(sp)
  2388.     move.l    _FSReq,-(sp)
  2389.     movea.l    d2,a0
  2390.     jsr    (a0)            ;d0 = (FSReq->filefunc)(FSReq, FSWin)
  2391.     addq.w    #8,sp
  2392.     tst.l    d0            ;Return 0?
  2393.      beq.s    1$            ;Yep
  2394.     move.w    #1,_fsvirgindir    ;Else re-read directory
  2395. 1$
  2396.     move.l    (sp)+,d2
  2397.     rts
  2398.  
  2399.  
  2400. ; VOID FSSetFileGads(VOID)
  2401. ;   Assign and render currently active file texts, disable remainder
  2402.  
  2403.     XDEF    _FSSetFileGads
  2404. _FSSetFileGads:
  2405.     movem.l    d4-d5,-(sp)
  2406.  
  2407.     move.w    _fsnumentries,d5    ;Grab number of entries
  2408.      beq.s    3$            ;No entries, nothing to set!
  2409.  
  2410. ; Update visible list based on topfin point in linked list
  2411.     jsr    _FSAssignNodes
  2412.  
  2413. ; Show all used gadgets
  2414.     moveq    #0,d4            ;i = 0
  2415.     bra.s    2$
  2416. 1$
  2417.     move.l    d4,-(sp)
  2418.     jsr    _FSEnableFGad
  2419.     addq.w    #4,sp
  2420.     addq.w    #1,d4            ;Bump gadget count
  2421. 2$
  2422.     cmpi.w    #10,d4            ;Hit highest gadget?
  2423.      bcc.s    3$            ;Yep, done
  2424.     cmp.w    d5,d4            ;Else, Hit last gadget?
  2425.      bcs    1$            ;Nope enable another
  2426. 3$
  2427.     movem.l    (sp)+,d4-d5
  2428.     rts
  2429.  
  2430.  
  2431. ; SetRootDir()
  2432. ; Chop off all subdirectory names contained in FSPathInfo, moving up to
  2433. ; root name if possible.  Flag to read new directory in any case.
  2434.  
  2435.     XDEF    _SetRootDir
  2436. _SetRootDir:
  2437. ;if ( (tstr = strchr(FSPathInfo.Buffer, ':')) != 0L)
  2438.     moveq    #':',d0
  2439.     movea.l    _FSPathInfo,a0
  2440.     jsr    aindex
  2441.     tst.l    d0
  2442.      beq.s    1$            ;Nope
  2443.  
  2444.     clr.b    1(a0)            ;Otherwise clobber the char after ':'
  2445.     move.w    #1,_fsvirgindir    ;virgindir = 1, read directory
  2446.  
  2447. 1$    rts
  2448.  
  2449.  
  2450. ; SetParentDir()
  2451. ;  Chop off last directory name contained in FSPathInfo, moving up one level
  2452. ; if possible.
  2453.  
  2454.     XDEF    _SetParentDir
  2455. _SetParentDir:
  2456.     movem.l    a2-a3,-(sp)
  2457.  
  2458. ;if (FSPathInfo.Buffer[0])
  2459.     movea.l    _FSPathInfo,a3    ;Grab pointer to path text
  2460.     tst.b    (a3)            ;Is it of zero length?
  2461.      beq.s    spddone            ;Yep, at root already
  2462.  
  2463. ;tstr = rindex(FSPathInfo.Buffer, '/')
  2464.     moveq    #'/',d0
  2465.     movea.l    a3,a0
  2466.     jsr    arindex
  2467.     tst.l    d0            ;Grab index to last occurance of slash
  2468.      bne.s    spdnotsub        ;If we got one that is
  2469.  
  2470. ; if ( tstr = rindex(FSPathInfo.Buffer, ':') )
  2471. ;     tstr++;
  2472.     moveq    #':',d0
  2473.     movea.l    a3,a0
  2474.     jsr    arindex            ;Grab index to last occurance of colon
  2475.     tst.l    d0
  2476.      beq.s    spdnotroot        ;Oops, no colon either, at top of path?
  2477.     addq.w    #1,a0            ;Move past the ':'
  2478.     bra.s    spdnotsub        ;Terminate the text
  2479. ;else
  2480. spdnotroot:
  2481.     movea.l    a3,a0            ;tstr = (BYTE *)FSPathInfo.Buffer
  2482.  
  2483. spdnotsub:
  2484.     clr.b    (a0)            ;*tstr = '\x0'
  2485.     move.w    #1,_fsvirgindir    ;virgindir = 1, read the new directory
  2486.  
  2487. spddone:
  2488.     movem.l    (sp)+,a2-a3
  2489.     rts
  2490.  
  2491.  
  2492. ;HCompGad(rp, g2)
  2493. ;  struct RastPort *rp;
  2494. ;  struct Gadget *g2;
  2495. ;
  2496. ;  Given a rastport and a gadget pointer, highlight or de-highlight
  2497. ; a gadget using RectFill in COMPLEMENT mode.
  2498.  
  2499. hrp    EQU    16
  2500. hgad    EQU    20
  2501.     XDEF    _HCompGad
  2502. _HCompGad:
  2503.     movem.l    d2-d3/a6,-(sp)
  2504.  
  2505.     movea.l    hrp(sp),a1
  2506.     moveq    #2,d0
  2507.     SYS    SetDrMd,_GfxBase     ;SetDrMd(rp, COMPLEMENT)
  2508.  
  2509.     movea.l    hgad(sp),a0        ;Grab gadget pointer
  2510.     moveq    #0,d0
  2511.     move.w    4(a0),d0        ;x0 = (ULONG)g2->LeftEdge
  2512.  
  2513.     move.l    d0,d2
  2514.     add.w    8(a0),d2
  2515.     subq.w    #1,d2            ;x1 = x0 + g2->Width - 1L
  2516.  
  2517.     moveq    #0,d1
  2518.     move.w    6(a0),d1        ;y0 = (ULONG)g2->TopEdge
  2519.  
  2520.     move.l    d1,d3
  2521.     add.w    10(a0),d3
  2522.     subq.w    #1,d3            ;y1 = y0 + g2->Height - 1L
  2523.  
  2524.     movea.l    hrp(sp),a1
  2525.     SYS    RectFill        ;RectFill(rp, x0, y0, x1, y1)
  2526.  
  2527.     movea.l    hrp(sp),a1
  2528.     moveq    #1,d0
  2529.     SYS    SetDrMd            ;SetDrMd(rp, JAM2)
  2530.  
  2531.     movem.l    (sp)+,d2-d3/a6
  2532.     rts
  2533.  
  2534.  
  2535. ;HCompEntry(num)
  2536. ;  LONG num;
  2537. ;
  2538. ;   Highlight or de-highlight a slot in the filename area, given its
  2539. ; entry number
  2540.  
  2541.     XDEF    _HCompEntry
  2542. _HCompEntry:
  2543.     movem.l    d2-d3/a2/a6,-(sp)
  2544.  
  2545.     movea.l    _FSRPort,a2        ;Grab window
  2546.  
  2547.     movea.l    a2,a1
  2548.     moveq    #2,d0
  2549.     SYS    SetDrMd,_GfxBase     ;SetDrMd(rp, COMPLEMENT)
  2550.  
  2551.     moveq    #5,d0            ;x0 = (ULONG)g2->LeftEdge
  2552.     move.l    #460,d2            ;x1 = x0 + g2->Width - 1L
  2553.  
  2554.     move.w    16+4+2(sp),d1
  2555.     mulu    #11,d1
  2556.     add.w    #12,d1            ;y0 = (ULONG)g2->TopEdge
  2557.  
  2558.     move.l    d1,d3
  2559.     add.w    #9,d3            ;y1 = y0 + g2->Height - 1L
  2560.  
  2561.     movea.l    a2,a1
  2562.     SYS    RectFill        ;RectFill(rp, x0, y0, x1, y1)
  2563.  
  2564.     movea.l    a2,a1
  2565.     moveq    #1,d0
  2566.     SYS    SetDrMd            ;SetDrMd(rp, JAM2)
  2567.  
  2568.     movem.l    (sp)+,d2-d3/a2/a6
  2569.     rts
  2570.  
  2571.  
  2572. ; VOID FSDoSortGadget(type)
  2573. ;   LONG type;
  2574.  
  2575. dosgtype    EQU    4+4*3
  2576.  
  2577.     XDEF    _FSDoSortGadget
  2578. _FSDoSortGadget:
  2579.     movem.l    d2/a2/a6,-(sp)
  2580.  
  2581.     movea.l    _FSReq,a0
  2582.     moveq    #0,d0
  2583.     move.w    fs_sorttype(a0),d0
  2584.     cmp.w    dosgtype+2(sp),d0
  2585.      beq    dosgsame
  2586.  
  2587. ; Unhighlight previous setting
  2588.     tst.w    d0            ;Alphabetize?
  2589.      bne.s    1$
  2590.     lea    _AlphaGad,a0
  2591.     bra.s    3$
  2592. 1$
  2593.     subq.w    #1,d0            ;FileSize?
  2594.      bne.s    2$
  2595.     lea    _SizeGad,a0
  2596.     bra.s    3$
  2597. 2$
  2598.     subq.w    #1,d0            ;Time?
  2599.      bne.s    4$            ;Nope, nosort previously
  2600.     lea    _TimeGad,a0
  2601. 3$
  2602.     bclr.b    #7,gg_Flags+1(a0)    ;gad->Flags &= ~SELECTED
  2603.  
  2604.     movea.l    _FSWin,a1
  2605.     suba.l    a2,a2
  2606.     moveq    #1,d0
  2607.     SYS    RefreshGList,_IntuitionBase ;RefreshGList(gad, FSWin, 0L, 1)
  2608. 4$
  2609. ; Set new sort type
  2610.     movea.l    _FSReq,a0
  2611.     move.l    dosgtype(sp),d1
  2612.     move.w    d1,fs_sorttype(a0)
  2613.  
  2614.     movea.l    _fnList,a0
  2615.     movea.l    MLH_HEAD(a0),a0
  2616.     tst.l    fn_Node+MLN_SUCC(a0)
  2617.      beq.s    dosgdone        ;No list, don't bother sorting
  2618.     tst.l    _topfin        ;Grab current topfin
  2619.      beq.s    5$            ;No currently visible files
  2620.     clr.w    _fsneedshow     ;fsneedshow = 0, needs sorting
  2621.     bra.s    6$
  2622. 5$
  2623.     move.w    #-1,_fsneedshow    ;No topfin, fsneedshow = -1
  2624. 6$
  2625. dossort:
  2626. ; Sort the list using the new sort type
  2627.     move.l    d1,-(sp)
  2628.     jsr    _SortNodes        ;SortNodes(type)
  2629.     addq.w    #4,sp
  2630.  
  2631.     jsr    _FSUpdateSort
  2632.  
  2633.     jsr    _FSWinTitle        ;Reset title to previous
  2634.     bra.s    dosgdone
  2635.  
  2636. dosgsame:
  2637.     move.w    #-1,fs_sorttype(a0)
  2638.  
  2639. dosgdone:
  2640.     movem.l    (sp)+,d2/a2/a6
  2641.     rts
  2642.  
  2643.  
  2644. ; SortNodes(key)
  2645. ;   LONG key;
  2646. ; Selection sort list of filenames using one of three key types
  2647.  
  2648.     XDEF    _SortNodes
  2649. _SortNodes:
  2650.     movem.l    d4/a2-a3/a6,-(sp)
  2651.  
  2652.     IFD    BENCHMARK
  2653.     jsr    _StartTime
  2654.     ENDC
  2655.  
  2656.     move.l    4+4*4(sp),d4        ;Grab our key type
  2657.      blt    snsortdone        ;No sort wanted
  2658.     cmpi.w    #1,_fsnumentries    ;More than one entry?
  2659.      ble    snsortdone        ;Nope, don't bother sorting
  2660.  
  2661.     move.w    _fstitstatus,-(sp)    ;Save old titstatus
  2662.     move.w    #28,_fstitstatus
  2663.     jsr    _FSWinTitle        ;FSWinTitle("Sorting...")
  2664.     move.w    (sp)+,_fstitstatus    ;Restore previous titlemsg
  2665.  
  2666. ; Convert Exec list to a simple head->next->NULL type
  2667.     movea.l    _fnList,a3        ;Grab old list
  2668.     movea.l    MLH_TAILPRED(a3),a1    ;a0 = last entry in list
  2669.     movea.l    MLH_HEAD(a3),a0
  2670.     clr.l    fn_Node+MLN_SUCC(a1)    ;Zap last nodes next field
  2671.  
  2672.     NEWLIST    a3            ;New the old list
  2673.  
  2674.     move.l    d4,d0            ;d0 = sorttype, a0 = headnode
  2675.     jsr    _FSListSort        ;list_sort(headnode, key) (a0/d0)
  2676.     movea.l    d0,a1            ;Grab new head of sorted list
  2677.  
  2678. ; Now add the new nodes back into the list
  2679.     movea.l    4,a6            ;Execbase calls
  2680.  
  2681. 1$    cmpa.l    #0,a1            ;Grab next node in new list
  2682.      beq.s    2$            ;End of list
  2683.     movea.l    fn_Node+MLN_SUCC(a1),a2    ;node = node->fn_Node.mln_Succ
  2684.  
  2685.     movea.l    a3,a0
  2686.     SYS    AddTail            ;AddTail(fnList, newnode)
  2687.  
  2688.     movea.l    a2,a1            ;a2 = next node
  2689.     bra    1$            ;Add the next node
  2690. 2$
  2691. snsortdone:
  2692.     IFD    BENCHMARK
  2693.     pea    _timermsg1
  2694.     jsr    _StopTime
  2695.     addq.w    #4,sp
  2696.     ENDC
  2697.  
  2698.     movem.l    (sp)+,d4/a2-a3/a6
  2699.     rts
  2700.  
  2701.  
  2702. ; struct file_node *FSListSort (list, type)
  2703. ;   struct file_node *list;
  2704. ;   long type;
  2705. ;
  2706. ;   Assumes a list of structures, with a pointer to "next" as the first
  2707. ;   field.  It reorders the list into ascending order, and returns the
  2708. ;   new first node's address.  It is order N log(N).
  2709. ;
  2710. ;   The compare routine should return 0 if the items are in order, and 1
  2711. ;   if they are not.  If the compare routine returns 0 in case of
  2712. ;   equality, the sort will be stable.
  2713. ;
  2714. ;   This routine depends upon compiler-dependant struct layout, but this
  2715. ;   assumption is likely to be fairly commonly valid.
  2716. ;
  2717. ;   The basic notion of this sort is to make sorted sublists longer and
  2718. ;   longer by merging.    On the Nth pass through the list, sorted
  2719. ;   sublists of length 2^(N-1) are produced.  Eventually, the entire
  2720. ;   list is sorted, in log2(N)+1 passes through the list.  There is
  2721. ;   extra bookkeeping overhead, but minimal extra storage space needed.
  2722. ;   Counts and clever pointer management substitute for extra "glue"
  2723. ;   nodes.
  2724. ;
  2725. ;   while more than one list
  2726. ;      while not at end of composite lists
  2727. ;         for each merge_length(m) block
  2728. ;           merge first items in lists onto current output list
  2729. ;         toggle current output list
  2730. ;
  2731. ; Register parameters:
  2732. ; struct file_node *FSListSort __ARGS((struct file_node *, LONG));
  2733. ;       d0                     a0         d0
  2734.  
  2735. flsold1    equ    -4
  2736. flsold0    equ    -8
  2737. flsnew1    equ    -12
  2738. flsnew0    equ    -16
  2739. flscnt1    equ    -20
  2740. flscnt0    equ    -24
  2741. flsffn1    equ    flscnt0-16
  2742. flsffn0    equ    flsffn1-16
  2743. flssend    equ    flsffn0-4
  2744.  
  2745.  
  2746.     XDEF    _FSListSort
  2747. _FSListSort:
  2748.     link    a5,#flssend
  2749.     movem.l    d2-d7/a2-a3,-(sp)
  2750.  
  2751.     move.l    d0,d3            ;d3 = sorttype
  2752.     clr.l    flsffn0+LN_SUCC(a5)    ;front[0].next = 0
  2753.     move.l    a0,flsffn1+LN_SUCC(a5)    ;front[0].next = list
  2754.  
  2755.     moveq    #1,d7            ;m = 1
  2756.     moveq    #0,d6            ;hm = 0
  2757.  
  2758. flsLoop1:
  2759.     tst.l    flsffn1+LN_SUCC(a5)    ;while (front[1].next)
  2760.      beq    flsdone
  2761.  
  2762.     lea    flsffn0(a5),a0
  2763.     move.l    a0,flsnew0(a5)        ;new[0] = &front[0]
  2764.     lea    flsffn1(a5),a0
  2765.     move.l    a0,flsnew1(a5)        ;new[1] = &front[1]
  2766.     move.l    flsffn0+LN_SUCC(a5),flsold0(a5)    ;old[0] = front[0].next
  2767.     move.l    flsffn1+LN_SUCC(a5),flsold1(a5)    ;old[1] = front[1].next
  2768.     clr.l    flscnt0(a5)        ;count[0] = 0
  2769.     clr.l    flscnt1(a5)        ;count[1] = 0
  2770.     moveq    #0,d4            ;n = 0
  2771.  
  2772.     moveq    #0,d5            ;items_merged = 0
  2773. flsLoop2:
  2774.     tst.l    flsold0(a5)        ;old[0]?
  2775.      bne.s    1$            ;Yep, get an item from this list
  2776.     tst.l    flsold1(a5)        ;old[1]?
  2777.      beq    flsNext2        ;Nope, both lists exhausted
  2778.  
  2779. 1$    cmp.l    d7,d5            ;if (items_merged >= m)
  2780.      bcs.s    2$            ;Nope, m > items_merged
  2781.     moveq    #0,d5            ;items_merged = 0
  2782.     bchg.l    #0,d4            ;n = 1 - n
  2783.     clr.l    flscnt0(a5)        ;count[0] = 0
  2784.     clr.l    flscnt1(a5)        ;count[1] = 0
  2785.  
  2786. 2$    tst.l    flsold0(a5)        ;old[0]?
  2787.      beq.s    3$
  2788.     tst.l    flsold1(a5)        ;old[1]?
  2789.      beq.s    3$
  2790.     cmp.l    flscnt0(a5),d6        ;count[0] < hm?
  2791.      bls.s    3$            ;Nope, hm >= count[0]
  2792.     cmp.l    flscnt1(a5),d6        ;count[1] < hm?
  2793.      bls.s    3$            ;Nope
  2794.  
  2795.     movea.l    flsold1(a5),a1
  2796.     movea.l    fn_info(a1),a1
  2797.     movea.l    flsold0(a5),a0
  2798.     movea.l    fn_info(a0),a0
  2799.     move.l    d3,d0
  2800.     jsr    _CompareNodes        ;CompareNodes(type, old[0]->info, old[1]->info)
  2801.     lsl.w    #2,d0            ;d0 = result of compare (0 or 1)
  2802.  
  2803.     move.w    d4,d1
  2804.     lsl.w    #2,d1            ;d1 = n<<2
  2805.     movea.l    flsnew0(a5,d1.w),a1    ;a1 = new[n]
  2806.     movea.l    flsold0(a5,d0.w),a0    ;a0 = old[o]
  2807.     move.l    a0,LN_SUCC(a1)        ;new[n]->next = old[o]
  2808.     move.l    LN_SUCC(a0),flsold0(a5,d0.w)  ;old[o] = old[o]->next
  2809.     addq.l    #1,flscnt0(a5,d0.w)    ;count[o]++
  2810.     bra.s    flsNext1
  2811. 3$
  2812. flselse1:
  2813.     tst.l    flsold0(a5)        ;old[0]?
  2814.      beq.s    2$            ;Nope, use old[1]
  2815.     cmp.l    flscnt0(a5),d6        ;count[0] < hm?
  2816.      bls.s    2$            ;Nope, count[0] >= hm, use old[1]
  2817. 1$    lea    flsold0(a5),a0        ;else a0 = &old[0]
  2818.     bra.s    3$
  2819. 2$    lea    flsold1(a5),a0        ;a0 = &old[1]
  2820. 3$
  2821.     move.w    d4,d1
  2822.     lsl.w    #2,d1
  2823.     movea.l    flsnew0(a5,d1.w),a1    ;a1 = new[n]
  2824.     move.l    (a0),LN_SUCC(a1)    ;new[n]->next = old[o]
  2825.     movea.l    (a0),a1
  2826.     move.l    LN_SUCC(a1),(a0)    ;old[o] = old[o]->next
  2827.  
  2828. flsNext1:
  2829.     move.w    d4,d0
  2830.     lsl.w    #2,d0
  2831.     movea.l    flsnew0(a5,d0.w),a0    ;a0 = new[n]
  2832.     move.l    LN_SUCC(a0),flsnew0(a5,d0.w) ;new[n] = new[n]->next
  2833.     addq.l    #1,d5            ;items_merged++
  2834.     bra    flsLoop2
  2835.  
  2836. flsNext2:
  2837.     movea.l    flsnew0(a5),a0
  2838.     clr.l    LN_SUCC(a0)        ;new[0]->next = 0
  2839.     movea.l    flsnew1(a5),a0
  2840.     clr.l    LN_SUCC(a0)        ;new[1]->next = 0
  2841.     move.l    d7,d6            ;hm = m
  2842.     lsl.l    #1,d7            ;m *= 2
  2843.     bra    flsLoop1
  2844.  
  2845. flsdone:
  2846.     move.l    flsffn0+LN_SUCC(a5),d0    ;return(front[0].next)
  2847.  
  2848.     movem.l    (sp)+,d2-d7/a2-a3
  2849.     unlk    a5
  2850.     rts
  2851.  
  2852.  
  2853. ; d0 = WORD CompareNodes(d0, a0, a1)
  2854. ;   WORD key = d0;
  2855. ;   struct node_data *a = a0, *b = a1;
  2856. ;
  2857. ; Compare data in two nodes, based upon key type.  Return boolean result
  2858. ; of the comparison in d0. Note that this is a register based function.
  2859.  
  2860.     XDEF    _CompareNodes
  2861. _CompareNodes:
  2862.     move.w    nd_filetype(a0),d1
  2863.     cmp.w    nd_filetype(a1),d1    ;Comparing same type of entries?
  2864.      beq.s    3$            ;Yep, use sort for compare
  2865.  
  2866.     btst.b    #3,_fsflags+1    ;Want files first?
  2867.      bne.s    2$            ;Yep
  2868.     btst.b    #4,_fsflags+1    ;Want dirs first?
  2869.      beq.s    3$            ;Don't care, see if there is a sort
  2870.  
  2871.     cmp.w    nd_filetype(a1),d1    ;Recompare
  2872.      bcs.s    cnmatch            ;a0->filetype = 2, a1->filetype = 1
  2873.     bra.s    cnnomatch        ;a0->filetype = 1, a1->filetype = 2
  2874. 2$
  2875.     cmp.w    nd_filetype(a1),d1    ;Recompare
  2876.      bhi.s    cnmatch            ;a0->filetype = 2, a1->filetype = 1
  2877.     bra.s    cnnomatch        ;a0->filetype = 1, a1->filetype = 2
  2878. 3$
  2879.     tst.w    d0
  2880.      blt.s    cnmatch            ;No sort, append to end
  2881.      bne.s    cnnotalpha        ;Not zero, not alphabetize
  2882.  
  2883. cnnalpha:
  2884.     pea    nd_alphadata+26(a1)
  2885.     pea    nd_alphadata+26(a0)
  2886.     jsr    _lstrcmp        ;return(lstrcmp(a->alphadata + 26L, b->alphadata + 26L) > 0)
  2887.     addq.w    #8,sp
  2888.     tst.w    d0
  2889.      ble.s    cnnomatch
  2890.     bra.s    cnmatch
  2891.  
  2892. cnnotalpha:
  2893.     cmpi.w    #1,d0            ;Sort by size?
  2894.      bne.s    cnnotsize        ;Nope, must be by date
  2895.  
  2896.     move.l    nd_filesize(a0),d0
  2897.     cmp.l    nd_filesize(a1),d0    ;return(a->filesize > b->filesize)
  2898.      beq    cnnalpha        ;Same size, sort alpha
  2899.      bcs.s    cnnomatch        ;a1 > a0
  2900.     bra.s    cnmatch
  2901.  
  2902. cnnotsize:
  2903.     move.l    nd_days(a0),d0
  2904.     cmp.l    nd_days(a1),d0        ;if (a->days > b->days)
  2905.      beq.s    cntstmins        ;Nope, a->days == b->days, check minutes
  2906.      bls.s    cnnomatch        ;Nope, a->days < b->days
  2907.     bra.s    cnmatch
  2908.  
  2909. cntstmins:
  2910. ;t1 = (a->minutes - b->minutes) * 3000L + (a->ticks - b->ticks)
  2911.     move.l    nd_minutes(a0),d0
  2912.     sub.l    nd_minutes(a1),d0
  2913.     muls    #3000,d0
  2914.  
  2915.     move.l    nd_ticks(a0),d1
  2916.     sub.l    nd_ticks(a1),d1
  2917.     add.l    d1,d0
  2918.  
  2919.     tst.l    d0            ;return(t1 > 0L);
  2920.      beq    cnnalpha        ;Same date, sort alpha
  2921.      bgt.s    cnmatch
  2922.  
  2923. cnnomatch:
  2924.     moveq    #0,d0
  2925.     bra.s    cndone
  2926.  
  2927. cnmatch:
  2928.     moveq    #1,d0
  2929. cndone:
  2930.     rts
  2931.  
  2932.  
  2933. ; LONG lstrcmp(astr, bstr)
  2934. ;   BYTE *astr, *bstr;
  2935. ;
  2936. ; Compare two texts for lexigraphic order, ignoring case differences
  2937.  
  2938.     XDEF    _lstrcmp
  2939. _lstrcmp:
  2940.     movem.l    4(sp),a0/a1        ;Grab astr, bstr
  2941.  
  2942. ;for(;*a && tolower(*a) == tolower(*b); a++, b++)
  2943. lccstart:
  2944.     move.b    (a0)+,d0        ;Grab a char from astr
  2945.     cmpi.b    #$40,d0            ;less than @ character?
  2946.      bls.s    1$            ;Yep
  2947.     cmpi.b    #$5a,d0            ;Greater than Z?
  2948.      bhi.s    1$            ;Yep
  2949.     addi.b    #$20,d0
  2950. 1$
  2951.     move.b    (a1)+,d1        ;Grab a char from bstr
  2952.     cmpi.b    #$40,d1            ;less than @ character?
  2953.      bls.s    2$            ;Yep
  2954.     cmpi.b    #$5a,d1            ;Greater than Z?
  2955.      bhi.s    2$            ;Yep
  2956.     addi.b    #$20,d1
  2957. 2$
  2958.     tst.b    d0            ;End of astr?
  2959.      beq.s    3$
  2960.     cmp.b    d1,d0            ;Are they the same character?
  2961.      beq    lccstart        ;Yep, compare next pair of chars
  2962. 3$
  2963.     sub.b    d1,d0            ;return(tolower(*astr) - tolower(*bstr))
  2964.     ext.w    d0
  2965.     ext.l    d0
  2966.     rts
  2967.  
  2968.  
  2969. ; Search a text for wild characters, return 1 if found
  2970.  
  2971.     XDEF    _iswild
  2972. _iswild:
  2973.     movea.l    4(sp),a0        ;Grab text pointer
  2974.     moveq    #0,d0            ;Clear out our character register
  2975. ischk1:
  2976.     move.b    (a0)+,d0        ;Grab a char
  2977.      beq.s    iswdone            ;Might be end of text?
  2978.     cmpi.b    #'*',d0            ;Is it *?
  2979.      beq.s    iswdone            ;yep, is wild
  2980.     cmpi.b    #'?',d0            ;Is it a qmark
  2981.      bne    ischk1            ;Nope, check next character
  2982.     rts                ;Otherwise it is wild
  2983.  
  2984. iswdone:
  2985.     rts
  2986.  
  2987.  
  2988.  
  2989. ; Compare a wild card name with a normal name
  2990. ; WORD wildmatch (name, wild)
  2991. ;   BYTE *name, *wild;
  2992.  
  2993.     XDEF    _wildmatch
  2994. _wildmatch:
  2995.     link    a5,#-64
  2996.     movem.l    d3/a2-a3,-(sp)
  2997.  
  2998.     movem.l    8(a5),a2-a3        ;Grab name/pattern
  2999.     lea    -64(a5),a0        ;back[0][0]
  3000.     lea    -60(a5),a1        ;back[0][1]
  3001.  
  3002.     moveq    #0,d3            ;bi = 0
  3003.  
  3004. wmloop1:
  3005.     tst.b    (a2)            ;End of name?
  3006.      bne.s    wmnoteon
  3007.     tst.b    (a3)            ;End of pattern?
  3008.      beq    wmmatched        ;Yep, we matched
  3009.  
  3010. wmnoteon:
  3011.     cmpi.b    #'*',(a3)        ;Is it a splat?
  3012.      bne.s    wmnotstar        ;Nope, maybe '?'
  3013.  
  3014.     cmpi.w    #64,d3            ;Have we hit max expression depth?
  3015.      beq    wmnomatch        ;Yep, ran out of room in recursion table
  3016.  
  3017. ;back[bi][0] = w
  3018.     move.l    a3,0(a0,d3.w)        ;Stash pointer to this '*' in table
  3019.  
  3020. ;back[bi][1] = n
  3021.     move.l    a2,0(a1,d3.w)
  3022.  
  3023.     addq.w    #8,d3            ;++bi
  3024.     addq.w    #1,a3            ;++w
  3025.     bra    wmloop1            ;Check next
  3026.  
  3027. wmgoback:
  3028.     subq.w    #8,d3            ;--bi
  3029.     move.l    a0,d0
  3030. wmback1:
  3031.     tst.w    d3            ;while (bi >= 0 && *back[bi][1] == '\x0')
  3032.      blt.s    wmbacked
  3033.     movea.l    0(a1,d3.l),a0
  3034.     tst.b    (a0)
  3035.      bne.s    wmbacked
  3036.  
  3037.     subq.w    #8,d3            ;--bi
  3038.     bra    wmback1
  3039.  
  3040. wmbacked:
  3041.     tst.w    d3            ;if (bi < 0)
  3042.      blt.s    wmnomatch        ;return (0)
  3043.  
  3044.     movea.l    d0,a0
  3045.     movea.l    0(a0,d3.w),a3        ;w = back[bi][0] + 1
  3046.     addq.w    #1,a3
  3047.  
  3048.     addq.l    #1,0(a1,d3.w)
  3049.     movea.l    0(a1,d3.l),a2        ;n = ++back[bi][1]
  3050.  
  3051.     addq.w    #8,d3            ;++bi
  3052.     bra    wmloop1
  3053.  
  3054. wmnotstar:
  3055.     cmpi.b    #'?',(a3)        ;Is it '?'
  3056.      bne.s    wmnotqmark
  3057.  
  3058.     tst.b    (a2)            ;Reached end of text?
  3059.      bne.s    wmincpoint        ;Nope, move on to next char
  3060.  
  3061.     tst.w    d3            ;Are we at top level of expression?
  3062.      beq.s    wmnomatch        ;Yep, expression didn't match
  3063.     bra    wmgoback        ;Otherwise pop a level and try to match
  3064.  
  3065. wmnotqmark:
  3066.     move.b    (a2),d0            ;Grab a char from bstr
  3067.     cmpi.b    #$40,d0            ;less than @ character?
  3068.      bls.s    1$            ;Yep
  3069.     cmpi.b    #$5a,d0            ;Greater than Z?
  3070.      bhi.s    1$            ;Yep
  3071.     addi.b    #$20,d0
  3072. 1$
  3073.     move.b    (a3),d1            ;Grab a char from bstr
  3074.     cmpi.b    #$40,d1            ;less than @ character?
  3075.      bls.s    2$            ;Yep
  3076.     cmpi.b    #$5a,d1            ;Greater than Z?
  3077.      bhi.s    2$            ;Yep
  3078.     addi.b    #$20,d1
  3079. 2$
  3080.     cmp.b    d0,d1            ;*n = *w?
  3081.      beq.s    wmincpoint        ;Yep, move on past
  3082.  
  3083.     tst.w    d3            ;Are we at top expression level?
  3084.      beq.s    wmnomatch        ;Yep, they didn't match
  3085.     bra    wmgoback        ;Nope, process next part
  3086.  
  3087. wmincpoint:
  3088.     tst.b    (a2)            ;Done with name?
  3089.      beq.s    wmnamend        ;Yep
  3090.     addq.w    #1,a2            ;Otherwise increment name pointer
  3091.  
  3092. wmnamend:
  3093.     tst.b    (a3)            ;End of pattern?
  3094.      beq.s    wmmatched        ;Yep, we matched
  3095.     addq.w    #1,a3            ;Otherwise inc wild pointer, match next char
  3096.     bra    wmloop1
  3097.  
  3098. wmmatched:
  3099.     moveq    #1,d0
  3100.     bra.s    wmdone
  3101.  
  3102. wmnomatch:
  3103.     moveq    #0,d0
  3104.  
  3105. wmdone:
  3106.     movem.l    (sp)+,d3/a2-a3
  3107.     unlk    a5
  3108.     rts
  3109.  
  3110.  
  3111.  
  3112. ; LONG MakePathString(lock, dest)
  3113. ;               a0     a1
  3114. ;   struct FileLock *lock;
  3115. ;   BYTE *dest;
  3116. ;
  3117. ; DESCRIPTION:
  3118. ;   Given text and a filelock, construct entire pathname and
  3119. ; return in dest.
  3120.  
  3121.     XDEF    _MakePathString
  3122. _MakePathString:
  3123.     link    a5,#0
  3124.     movem.l    d2-d5/d7/a2-a3/a6,-(sp)
  3125.  
  3126. ; Grab pointer to lock and dest text to fill
  3127.     move.l    8(a5),d3        ;d3 = lock
  3128.     movea.l    12(a5),a2        ;a2 = dest
  3129.     clr.b    (a2)            ;NULL terminate dest
  3130.     moveq    #0,d5            ;LockFlag = 0
  3131.  
  3132. ; Allocate a FileInfoBlock for local use
  3133.     moveq    #0,d1
  3134.     move.l    #fib_SIZEOF,d0
  3135.     SYS    AllocMem,4        ;AllocMem(sizeof(fib), 0L)
  3136.     move.l    d0,d7            ;d7 = *fib
  3137.      beq    mpsfailed        ;Whoops no mem? return!
  3138.  
  3139.     movea.l    _DOSBase(a4),a6        ;DOSBase calls from here on
  3140.  
  3141. ; while (lock != 0)
  3142. 1$
  3143.     tst.l    d3            ;Got a lock?
  3144.      beq.s    mpsokay            ;Nope, must be at root
  3145.  
  3146. ; Examine the current lock
  3147.     move.l    d3,d1
  3148.     move.l    d7,d2
  3149.     SYS    Examine            ;Examine(lock, fib)
  3150.     tst.l    d0            ;Okay?
  3151.      beq.s    mpsfailed        ;Nope, some sort of dos failure?
  3152.  
  3153.     movea.l    d7,a1
  3154.     cmpi.b    #' ',fib_FileName(a1)    ;if (fib->fib_FileName[0] >= ' ')
  3155.      bcs.s    3$            ;Nope, don't bother inserting?
  3156.  
  3157.     tst.b    (a2)            ;if (dest[0] != 0)
  3158.      beq.s    2$
  3159.     lea    _SlashStr(a4),a1
  3160.     movea.l    a2,a0
  3161.     jsr    _InsertPathString    ;InsertPathString(dest, "/");
  3162. 2$
  3163.     movea.l    d7,a1
  3164.     lea    fib_FileName(a1),a1
  3165.     movea.l    a2,a0
  3166.     jsr    _InsertPathString    ;InsertPathString(dest, fib->fib_FileName)
  3167. 3$
  3168. ; Okay, move up one directory
  3169.     move.l    d3,d4            ;oldlock = lock
  3170.  
  3171.     move.l    d3,d1
  3172.     SYS    ParentDir
  3173.     move.l    d0,d3            ;lock = ParentDir(lock)
  3174.  
  3175.     tst.w    d5            ;LockFlag set?
  3176.      bne.s    4$            ;Yep, unlock
  3177.     moveq    #1,d5            ;Else LockFlag = 1, unlock next time
  3178.      bra    1$            ;Next directory up
  3179. 4$
  3180.     move.l    d4,d1
  3181.     SYS    UnLock            ;UnLock(oldlock)
  3182.     bra    1$            ;Examine
  3183.  
  3184. mpsokay:
  3185. ; See if root was RAM:, special case
  3186.     movea.l    d7,a1            ;a1 = fib
  3187.     cmpi.b    #' ',fib_FileName(a1)    ;if (fib->fib_FileName[0] >= ' ')
  3188.      bcc.s    1$            ;Yep, not 1.1/1.2 RAM:
  3189.     lea    _RamDirNameStr(a4),a1    ;Else...
  3190.     movea.l    a2,a0
  3191.     jsr    _InsertPathString    ;InsertPathString(dest, "RAM:")
  3192.     bra.s    mpsdone
  3193. 1$
  3194. ; Find last slash we tacked on, change to a colon, or, add a colon
  3195.     moveq    #'/',d0
  3196.     movea.l    a2,a0
  3197.     jsr    aindex            ;d0 = strchr(dest, '/')
  3198.     tst.l    d0            ;Do we have a slash?
  3199.      beq.s    2$            ;Nope, at root....
  3200.     movea.l    d0,a0
  3201.     move.b    #':',(a0)        ;Else change first '/' to a ':'
  3202.     bra.s    mpsdone
  3203.  
  3204. ; No slash, must be locked at the root.  Append a colon to the dest.
  3205. 2$
  3206.     lea    _ColonStr(a4),a1
  3207.     movea.l    a2,a0
  3208.     jsr    astrcat            ;strcat (dest, ":")
  3209.     bra.s    mpsdone
  3210.  
  3211. ; Come here if an error occured, return empty text to caller
  3212. mpsfailed:
  3213.     clr.b    (a2)            ;dest[0] = (BYTE)0
  3214.     moveq    #0,d3            ;return (0L)
  3215.     bra.s    mpsdeall
  3216.  
  3217. ; Come here if everything is okay, deallocate FileInfoBlock
  3218. mpsdone:
  3219.     moveq    #1,d3            ;return (1L)
  3220.  
  3221. mpsdeall:
  3222.     tst.l    d7            ;Did we allocate a fib?
  3223.      beq.s    mpsfinis        ;nope
  3224.     movea.l    d7,a1            ;Else free the memory
  3225.     move.l    #fib_SIZEOF,d0
  3226.     SYS    FreeMem            ;FreeMem(fib, sizeof(fib))
  3227.  
  3228. mpsfinis:
  3229.     move.l    d3,d0            ;Put return value in d0
  3230.     movem.l    (sp)+,d2-d5/d7/a2-a3/a6
  3231.     unlk    a5
  3232.     rts
  3233.  
  3234.  
  3235. ; VOID InsertPathString(dest, source)
  3236. ;             a0    a1
  3237. ;   BYTE *dest, *source;
  3238. ;
  3239. ; DESCRIPTION:
  3240. ;   Insert source text into dest text.
  3241. ; Special case for source length == 0, source must be RAM.
  3242.  
  3243.     XDEF    _InsertPathString
  3244. _InsertPathString:
  3245.     movem.l    d7/a2-a3,-(sp)
  3246.  
  3247.     movea.l    a1,a3            ;a3 = source
  3248.     move.l    a0,a2            ;a2 = dest
  3249.  
  3250.     movea.l    a3,a0
  3251.     jsr    astrlen
  3252.     move.l    d0,d7            ;d7 = strlen(source)
  3253.  
  3254. 1$    movea.l    a2,a0
  3255.     jsr    astrlen            ;d0 = strlen(dest)
  3256.  
  3257.     addq.w    #1,d0            ;Bump the length to include zero byte at end
  3258.     movea.l    a2,a1
  3259.     adda.w    d7,a1            ;Push dest + slen
  3260.     movea.l    a2,a0            ;Push dest
  3261.     jsr    amovmem            ;amovmem(dest, dest + slen, strlen(dest) + 1)
  3262.  
  3263.     move.w    d7,d0
  3264.     movea.l    a2,a1
  3265.     movea.l    a3,a0
  3266.     jsr    amovmem            ;amovmem(source, dest, slen)
  3267.  
  3268.     movem.l    (sp)+,d7/a2-a3
  3269.     rts
  3270.  
  3271.  
  3272. ; BYTE *myrindex(text, searchchar)
  3273. ;   BYTE *text;
  3274. ;   LONG searchchar;
  3275. ;
  3276. ; C stack version of arindex.
  3277.  
  3278.     XDEF    _myrindex
  3279. _myrindex:
  3280.     movea.l    4(sp),a0
  3281.     move.l    8(sp),d0
  3282.  
  3283.  
  3284. ; BYTE *aindex(BYTE *, BYTE);
  3285.  
  3286.     XDEF    aindex
  3287. aindex:
  3288. 1$    cmp.b    (a0),d0
  3289.      beq.s    aifound
  3290.     tst.b    (a0)+
  3291.      beq.s    ainomatch
  3292.     bra    1$
  3293.  
  3294. ainomatch:
  3295.     moveq    #0,d0
  3296.     rts
  3297.  
  3298. aifound:
  3299.     move.l    a0,d0
  3300.     rts
  3301.  
  3302.  
  3303. ; BYTE *arindex(BYTE *, BYTE);
  3304.  
  3305.     XDEF    arindex
  3306. arindex:
  3307.     move.l    a0,d1            ;Copy start of string for compares
  3308.  
  3309. 1$    tst.b    (a0)+            ;Find end of text
  3310.      bne    1$
  3311.  
  3312. 2$    cmp.b    -(a0),d0        ;Now work backward comparing along the way
  3313.      beq.s    rifound            ;..Until we find a match
  3314.     cmpa.l    d1,a0            ;...or hit the beginning of the text
  3315.      bgt    2$
  3316.  
  3317. rinomatch:
  3318.     moveq    #0,d0
  3319.     rts
  3320.  
  3321. rifound:
  3322.     move.l    a0,d0
  3323.     rts
  3324.  
  3325.  
  3326. ;  d0         a0
  3327. ; LONG astrlen(text)
  3328. ;   BYTE *text;
  3329. ;
  3330. ; Synopsis: Calculate length of null-byte terminated text.
  3331. ; a0 returns pointing to null char at end of text
  3332. ; d0 returns number of bytes in the text
  3333.  
  3334.     XDEF    astrlen
  3335. astrlen:
  3336.     move.l    a0,d0            ;Save initial address
  3337. 1$    tst.b    (a0)+            ;Test a byte for zero-ness
  3338.      bne    1$
  3339.  
  3340.     suba.l    d0,a0            ;Minus initial address
  3341.     subq.w    #1,a0            ;Less one for overshoot
  3342.     exg    d0,a0            ;swap em
  3343.     rts
  3344.  
  3345.  
  3346. ; astrcat()
  3347. ; Takes text in a0, appends text in a1
  3348. ; a0 returns pointing to null at end of final text
  3349.  
  3350.     XDEF    astrcat
  3351. astrcat:
  3352. ; Find end of first text
  3353. 1$    tst.b    (a0)+
  3354.      bne    1$
  3355.     subq.w    #1,a0            ;Back up to null char
  3356.  
  3357. ; Append second text
  3358. 2$    move.b    (a1)+,(a0)+
  3359.      bne    2$
  3360.     subq.w    #1,a0            ;a0 = the null at end of final text
  3361.     rts
  3362.  
  3363.  
  3364. ; astrcpy()
  3365. ; Takes text in a0, copies text in a1
  3366. ; a0 returns pointing to null at end of final text
  3367.  
  3368.     XDEF    astrcpy
  3369. astrcpy:
  3370. ; Copy second text
  3371. 1$    move.b    (a1)+,(a0)+
  3372.      bne    1$
  3373.     subq.w    #1,a0            ;Back up to null
  3374.     rts
  3375.  
  3376.  
  3377. ; astrcmp()
  3378. ; Takes text in a0, compares to text in a1
  3379. ; a0 returns pointing to first difference, d0 contains the difference
  3380. ; or zero if the two texts are identical
  3381.  
  3382.     XDEF    astrcmp
  3383. astrcmp:
  3384. 1$    move.b    (a0)+,d0        ;Grab a char from A
  3385.     move.b    (a1)+,d1        ;Grab a char from B
  3386.     tst.b    d0            ;Hit end of A?
  3387.      beq.s    2$            ;Yep, diff em
  3388.     cmp.b    d1,d0            ;Else the same char?
  3389.      beq    1$            ;Compare next pair
  3390. 2$    sub.b    d1,d0            ;A - B
  3391.     ext.w    d0
  3392.     ext.l    d0
  3393.     rts
  3394.  
  3395.  
  3396. ; safestrcpy(dest, source, length)
  3397. ;   Copies at most length chars of source to dest, if source < length
  3398. ; don't pad with nulls like strncpy.  Always null terminates dest.
  3399.  
  3400.     XDEF    _safestrcpy
  3401. _safestrcpy:
  3402.     movem.l    4(sp),a0/a1        ;Grab dest and source pointers
  3403.     move.w    14(sp),d0        ;Grab count
  3404.  
  3405.  
  3406. ; astrncpy()
  3407. ; Takes text in a1, copies d0 bytes to text in a0.
  3408. ; a0 returns pointing to null at end of final text.
  3409. ; Dest text is always null terminated.
  3410.  
  3411.     XDEF    astrncpy
  3412. astrncpy:
  3413. 1$    move.b    (a1)+,(a0)+
  3414. 2$    dbeq    d0,1$
  3415.     subq.w    #1,a0
  3416.     clr.b    (a0)            ;Null terminate dest
  3417.     move.l    a0,d0
  3418.     rts
  3419.  
  3420.  
  3421. ; amovmem()
  3422. ; Takes text in a0, copies d0 bytes to text in a1. Correctly handles
  3423. ; overlapping memory.
  3424.  
  3425.     XDEF    amovmem
  3426. amovmem:
  3427.     cmpa.l    a0,a1            ;Low to high or high to low?
  3428.      bcs.s    2$            ;High to low, copy forward
  3429.     adda.w    d0,a0            ;Else start at end, copy backward
  3430.     adda.w    d0,a1
  3431.  
  3432. 1$    move.b    -(a0),-(a1)
  3433.     subq.w    #1,d0
  3434.      bgt    1$
  3435.     bra.s    amdone
  3436.  
  3437. 2$    move.b    (a0)+,(a1)+
  3438.     subq.w    #1,d0
  3439.      bgt    2$
  3440. amdone:
  3441.     rts
  3442.  
  3443.     END
  3444.  
  3445. #endasm
  3446.  
  3447. #endif    /* PATHMASTER */
  3448.